Whilst you can use unittest with scripts and ad-hoc code, the main use-case is for adding tests to packages.
For the following example we’ll assume you’re developing a package called mypackage
.
Add the following line to the package DESCRIPTION
file, to declare that your package optionally depends on unittest
:
Suggests: unittest
Create a directory called tests
in your package source, alongside your R
directory.
Let’s say we want to test the following package function, in R/biggest.R
:
biggest <- function(x,y) {max(c(x,y))}
Create a corresponding tests/test_biggest.R
in your package source (the file name isn’t important, but it helps to be consistent):
#!/usr/bin/Rscript --vanilla
library(mypackage)
library(unittest, quietly = TRUE)
if (!interactive()) options(warn=2, error = function() { sink(stderr()) ; traceback(3) ; q(status = 1) })
ok(ut_cmp_equal( biggest(3,4), 4), "two numbers")
ok(ut_cmp_equal( biggest(c(5,3),c(3,4)), 5), "two vectors")
The if (!interactive()) ...
line makes sure that, when run as a script, any warnings are errors, so they don’t go unnoticed. We also enable a traceback so you can see where any errors occured.
Finally, we use ok
to test the output of the function works as we expect.
There are many ways you can then run your tests:
R CMD check
will run everything it finds in the tests
directory, and will fail if any of the tests fail.source('tests/test_biggest.R')
within R will run individual tests in your current R session.Rscript --vanilla tests/test_biggest.R
will run the test outside of R.tests/test_biggest.R
will also run the test outside of R, if the file is marked as executable (i.e. chmod a+x tests/test_biggest.R
).unittest
detects when it’s been run as a script and if so will produce a summary of a results. The package will also throw an error if any tests fail; throwing an error will in turn cause CMD check
to report the error and fail the check
.
To run all your tests as part of a bash script, you can do so with:
for f in tests/*.R; do echo "=== $f"; Rscript --vanilla $f || break; done
unittest will output colored diff output if it thinks it will be supported. By default it assumes that they are not supported in R CMD check
. If you would like to see a log in color you can do the following:
R_CLI_NUM_COLORS=256 R CMD check ...
less -R 00check.log
Sometimes it’s necessary to test functions that aren’t exported by your package. Because they aren’t exported they cannot be directly referenced in tests. To get around this, use local()
as follows:
var <- 4
local({
ok(ut_cmp_equal(internal_function(3), 3))
ok(ut_cmp_equal(internal_function(var), 4))
# NB: Regular assignment (<-) won't work here,
# but using <<- to refer to variables outside local() will
var <<- 5
ok(ut_cmp_equal(internal_function(var), 5))
}, asNamespace('mypackage'))
At the start of your vignette, load unittest but customise ok()
so it’s output goes to stderr:
```{r, message=FALSE, echo=FALSE}
library(unittest)
# Redirect ok() output to stderr
options(unittest.output = stderr())
library(mypackage)
```
Then, include hidden blocks for your tests, for example:
Our biggest function will return the highest number:
```{r}
out <- biggest(3,4)
out
```
```{r, message=FALSE, echo=FALSE}
ok(ut_cmp_equal(out, 4), "biggest(3,4) is 4")
```
Here, the reader sees the first block, and the output of biggest()
, and the hidden block ensures the output is as we expect.
To run the tests, build the vignettes with, e.g. tools::buildVignettes(dir=".")
. Test output will be shown as part of the rebuild process.