This repository goes through how to set up unit testing using two popular R packages: RUnit and testthat.
- Create a directory called
tests
where all test files will be stored. - Create a file named
runit01.r
(or any name that starts with "runit") to contain the first set of tests. - Write the test functions (the function name must begin with "test", such as
test.c2f
). Remember that they are called unit tests for a reason, so make sure that each test function relates to only a single part of the package. - As new features are developed, new bugs are found, or new edge cases are discovered, continue creating new tests to account for these.
test.c2f <- function() {
# check functions...
}
checkEquals
: Are two objects equal, including named attributes?checkEqualsNumeric
: Are two numeric values equal?checkIdentical
: Are two objects exactly the same?checkTrue
: Does an expression evaluate to TRUE?checkException
: Does an expression raise an error?
Create a file named run_tests.r
outside of the tests
directory. This file will invoke all of the unit tests from the tests
directory. Below is an example of run_tests.r
.
library(runit)
# other packages required for testing
source(...) # other functions/code to test
testsuite.c2f <- defineTestSuite(name = "c2f",
dirs = file.path("tests"))
test.result <- runTestSuite(testsuite.c2f)
printTextProtocol(test.result)
The defineTestSuite
function takes the following arguments:
defineTestSuite(name, dirs, testFileRegexp = "^runit.+\\.[rR]$",
testFuncRegexp = "^test.+",
rngKind = "Marsaglia-Multicarry",
rngNormalKind = "Kinderman-Ramage")
name
is the name of the test suite, and dirs
is a vector of absolute directory names where the test files are located (absolute directory names are achieved by the file.path
command).
When specifying testFileRegexp
and testFuncRegexp
for unique test file and test function naming schemes, use regular expressions.
^
represents the start of the current line.$
represents the end of the current line.- Specifying
testFileRegexp = "^runit.+\\.[rR]$"
indefineTestSuite
means that all test files begin with "runit" and end with ".r".
Calling printTextProtocol(test.result)
will print the test results to the console, outlining which tests passed or failed.
The structure of the unit testing directories should look like this:
code-runit
├── inspect-example.R
├── run_tests.R
├── sample.R
└── tests
├── runit01.R
├── runit02.R
└── runit03.R
The testthat
package by Hadley Wickham is an alternative to the RUnit package. While testthat
does not follow the syntax of xUnit variants, it is very flexible and easier to read and comprehend.
- Create a directory called
tests
where all test files will be stored. - Create a file named
test01.r
(or any name that starts with "test") to contain the first set of tests. - Write the tests, following the structure below. Each test begins with
test_that
, followed by a short description of the test and the "expectations" of the test.
context("name of test")
test_that("str_length is number of characters", {
expect_equal(str_length("a"), 1)
expect_equal(str_length("ab"), 2)
expect_equal(str_length("abc"), 3)
})
test_that("a second test", {
...
})
Similar to the check
functions in RUnit, expectations all start with expect_
.
expect_equal(actual, expected)
: equality within numerical toleranceexpect_identical(actual, expected)
: exact equivalenceexpect_match(string, "Testing")
: matches a character vector against a regular expression. Below are variations on expect_matchexpect_output()
expect_message()
expect_warning()
expect_error()
expect_is(object, "class")
: checks that object inherits from the specified classexpect_true()
: hopefully you get the pattern by nowexpect_false()
: ditto above
Create a file named run_tests.R
outside of tests
directory.
# run_tests.R
library(testthat)
# other packages/sources needed to test
source("sample.R")
test_dir("tests", reporter = "Summary")
Running test_dir
will invoke all of the tests, and print a summary of the test results. The context is printed, then the success or failure of each expectation, represented by dots (".") for success or a number for failure. testthat
then summarizes the failed test.
The structure of the unit testing directories should look like this:
code-testthat/
├── run_tests.R
├── sample.R
└── tests
├── test1.R
├── test2.R
└── test3.R