--- title: "Frequently Asked Questions" output: html_document: toc: true vignette: > %\VignetteIndexEntry{Frequently Asked Questions} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- ```{r, message=FALSE, echo=FALSE} library(unittest) ``` ## General ### How do I test error conditions? Use the ``ut_cmp_error`` function. For example, here is a function that will throw an error for a bad argument: ```{r} add_four <- function(x) { if( ! is.numeric(x) ) stop("x must be numeric") return( x+4 ) } ``` We can test the argument check like this: ```{r} ok(ut_cmp_error(add_four("a"), "must be numeric"), "add_four() argument not numeric throws error") ``` ### How do I test if a warning is issued? Use the ``ut_cmp_warning`` function. For example, here is a function that will issue a warning if an argument contains ``NA``: ```{r} has_similar_mean <- function(x, y, tol = 0.5) { if( any(is.na(x)) ) warning("x contains NAs", call. = FALSE) if( any(is.na(y)) ) warning("y contains NAs", call. = FALSE) return( isTRUE(all.equal(mean(x), mean(y), tolerance = tol)) ) } ``` We can test for a warning like this: ```{r} ok(ut_cmp_warning(has_similar_mean(c(1,2,3,4), c(1,NA,5)), "y contains NAs"), "has_similar_mean() NAs in y issues a warning") ``` We can check for multiple distinct warnings ```{r} ok(ut_cmp_warning(has_similar_mean(c(NA,2,3,4), c(1,NA,5)), expected_regexp = c("x contains NAs", "y contains NAs"), expected_count = 2L), "has_similar_mean() NAs in arguments issue warnings") ``` Here we could use the same regexp to match both wrnings ```{r} ok(ut_cmp_warning(has_similar_mean(c(NA,2,3,4), c(1,NA,5)), "^[xy] contains NAs", expected_count = 2L), "has_similar_mean() NAs in arguments issue warnings") ``` ### How do I test multivalue results, or see differences? Use ``ut_cmp_equal(...)`` or ``ut_cmp_identical(...)`` as replacements for ``all.equal(...)`` and ``identical(...)`` respectively: ```{r} a <- c(1,2,3) b <- 1:3 ok(ut_cmp_equal(a,b), "a and b are equal") ``` ``ut_cmp_identical`` will make sure your objects are identical, and is more useful when comparing e.g. a list of strings which should be exactly the same. ``ut_cmp_equal`` will test for ‘near equality’, and is more useful when comparing numeric values which may be slightly different due to floating-point accuracy. Either way, if your test fails you will get verbose output showing you how they differ, and if you have git installed the output will be coloured. For example:
> ok(ut_cmp_equal(c(1,2,3,4,5), c(1,8,8,4,5))) not ok - ut_cmp_equal(c(1, 2, 3, 4, 5), c(1, 8, 8, 4, 5)) # Test returned non-TRUE value: # Mean relative difference: 2.2 # --- c(1, 2, 3, 4, 5) # +++ c(1, 8, 8, 4, 5) # [1] 1 [-2 3-]{+8 8+} 4 5### Grouping tests When dealing with many unit tests in one file it can be useful to group related unit tests. The ``ok_group()`` function is used like this: ```{r} ok_group("Test addition", { ok(1 + 1 == 2, "Can add 1") ok(1 + 3 == 4, "Can add 3") }) ok_group("Test subtraction", { ok(1 - 1 == 0, "Can subtract 1") ok(1 - 3 == -2, "Can subtract 3") }) ``` x You can use ``local()`` to ensure that state is localized within an ``ok_group`` ```{r} ok_group("Test adding integers", local({ x <- 1L; y <- 2L ok(x + y == 3L, "Can add integer variables") })) ``` ### I am sure I do not need to test my code. Is this true? No. Sit down and have a cup of tea. Hopefully the feeling will go away.