LibraryTesting Your Package

Testing Your Package

Learn about Testing Your Package as part of R Programming for Statistical Analysis and Data Science

Testing Your R Package

Robust testing is a cornerstone of developing high-quality R packages. It ensures your code functions as expected, prevents regressions, and builds confidence for users. This module will guide you through the essential aspects of testing your R package, focusing on the

code
testthat
package, a widely adopted framework for unit testing in R.

Why Test Your R Package?

Testing serves multiple critical purposes in package development:

  • Ensuring Correctness: Verifies that your functions produce the expected outputs for given inputs.
  • Preventing Regressions: Catches unintended side effects when you modify or add new code.
  • Improving Code Quality: Encourages writing modular, well-defined, and maintainable code.
  • Facilitating Collaboration: Provides a clear contract for how your package should behave, making it easier for others to contribute or use.
  • Building User Trust: Demonstrates that your package has undergone rigorous validation.

Introduction to `testthat`

code
testthat
is the de facto standard for unit testing in R. It provides a simple yet powerful framework for writing tests, asserting conditions, and reporting results. The core idea is to write small, independent tests that verify specific pieces of your code (units).

`testthat` uses a clear, readable syntax for writing tests and assertions.

Tests are typically written in files within a tests/testthat/ directory. Each test file contains one or more test cases, often grouped by the function or feature they are testing. testthat provides functions like test_that(), expect_equal(), expect_true(), and expect_error() to structure and execute these tests.

A typical test file might look like this:

# tests/testthat/test-my_function.R

library(testthat)
library(your_package_name)

test_that("my_function works with positive numbers", {
  expect_equal(my_function(2, 3), 5)
})

test_that("my_function handles zero input", {
  expect_equal(my_function(0, 5), 5)
})

test_that("my_function throws an error for negative input", {
  expect_error(my_function(-1, 5))
})

When you run devtools::test(), testthat discovers and executes these tests, reporting any failures or errors.

Key `testthat` Assertions

Assertion FunctionPurposeExample Usage
expect_equal(object, expected)Checks if two objects are identical.expect_equal(sum(1:5), 15)
expect_identical(object, expected)Checks if two objects are identical in both value and type.expect_identical(list(1, 'a'), list(1, 'a'))
expect_true(condition)Checks if a condition evaluates to TRUE.expect_true(is.numeric(my_variable))
expect_false(condition)Checks if a condition evaluates to FALSE.expect_false(is.null(my_variable))
expect_error(expression, regexp = NULL)Checks if an expression throws an error. Optionally checks the error message.expect_error(stop('Error message'), 'Error message')
expect_warning(expression, regexp = NULL)Checks if an expression throws a warning. Optionally checks the warning message.expect_warning(warning('Warning message'), 'Warning message')
expect_output(expression, regexp = NULL)Checks the standard output of an expression.expect_output(print('Hello'), 'Hello')

Running Your Tests

The most convenient way to run your package tests is using the

code
devtools
package. Ensure you have
code
devtools
installed (
code
install.packages('devtools')
). Within your package's root directory, you can run:

  • code
    devtools::test()
    : Runs all tests in the
    code
    tests/testthat/
    directory.
  • code
    devtools::test(filter = "test-my_function.R")
    : Runs only tests in a specific file.
  • code
    devtools::test(filter = "my_function")
    : Runs tests that contain the string "my_function" in their name.

It's a good practice to run your tests frequently, ideally before committing changes and as part of your continuous integration (CI) pipeline.

Best Practices for Writing Tests

  • Test one thing at a time: Each test should focus on a single behavior or condition.
  • Make tests independent: Tests should not rely on the outcome of other tests.
  • Test edge cases: Consider boundary conditions, invalid inputs, and error scenarios.
  • Keep tests fast: Slow tests can discourage frequent execution.
  • Test public API: Focus on testing the functions that users will interact with directly.
  • Use descriptive test names: Clearly indicate what each test is verifying.

Beyond Unit Tests: Integration and Examples

While unit tests are crucial, consider other forms of testing:

  • Integration Tests: Verify that different parts of your package work together correctly.
  • Example Tests:
    code
    testthat
    can also run the examples provided in your package's documentation (`
R
# tests/testthat/test-examples.R
library(testthat)
library(your_package_name)
context("Package Examples")
example("my_function", package = "your_package_name", run_dontrun = TRUE)

This ensures your documentation examples are up-to-date and functional.

  • Vignettes: While not strictly tests, well-written vignettes serve as extended examples and can be checked for correctness.

The testthat framework provides a structured way to write and run tests. A test file typically begins with loading the necessary libraries and then uses test_that() to define individual test cases. Inside each test_that() block, assertion functions like expect_equal() are used to compare actual results with expected outcomes. This systematic approach helps in identifying and fixing bugs efficiently.

📚

Text-based content

Library pages focus on text content

Learning Resources

testthat: Unit Testing for R(documentation)

The official documentation for the testthat package, providing comprehensive guides and function references.

R Packages: Testing(documentation)

A chapter from the 'R Packages' book, offering a practical and in-depth explanation of testing R packages with testthat.

Writing Good R Unit Tests(blog)

A blog post that provides practical advice and best practices for writing effective unit tests in R.

Testing R Packages with testthat(video)

A video tutorial demonstrating how to set up and write tests for an R package using testthat.

R-hub: Package Testing(documentation)

Information on package testing within the R-hub ecosystem, which is crucial for CRAN submissions.

Introduction to testthat(documentation)

The introductory vignette for testthat, explaining its core concepts and usage.

R-Ladies Global: Testing Your R Code(blog)

A blog post from R-Ladies that covers the basics of testing R code, including an introduction to testthat.

testthat: Assertions(documentation)

A reference page detailing the various assertion functions available in testthat for checking conditions.

R-hub: Building R Packages(documentation)

While not solely about testing, this guide covers the broader context of building R packages, including testing as a critical step.

The Art of R Programming: Testing(tutorial)

A tutorial that explains the importance of testing in R programming and introduces basic testing concepts.