Not minor. I've spent almost an equal amount of time fixing those issues in the past couple of years as I have actually developing code. Containerization freed me from caring about the state of everyone else's laptop, and allowed me to get back to work.
— Dr Mark Greenaway (@certifiedwaif) January 15, 2020
‘I started using automated tests because I discovered I was spending too much time re-fixing bugs that I’d already fixed before.’ - from Testing in R Packages (Wickham 2015)
context("String length") library(stringr) 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("str_length of factor is length of level", { expect_equal(str_length(factor("a")), 1) expect_equal(str_length(factor("ab")), 2) expect_equal(str_length(factor("abc")), 3) })
testing object | description | function |
---|---|---|
expectation | atom of testing | expect_* |
test | a collection of expectations | test_that |
context | a collection of tests | context |
# test for fixed positive number log(3)
## [1] 1.098612
# test for random positive number x <- rexp(1) # the exponential distribution only produces positive numbers log(x)
## [1] -2.978422
# test for fixed negative number log(-3)
## Warning in log(-3): NaNs produced
## [1] NaN
# test for random netgative number x <- -rexp(1) # the exponential distribution only produces positive numbers log(x)
## Warning in log(x): NaNs produced
## [1] NaN
# test for ugly string input log("pig")
## Error in log("pig"): non-numeric argument to mathematical function
# test for random string input x <- c("cat", "pig", "bird") %>% sample(1) log(x)
## Error in log(x): non-numeric argument to mathematical function
When developing, we won’t test the good, the bad, and the ugly.
a minimal development test
A neet test checks the function outputs a non-empty thing of expected type.
# make a package in rstudio usethis::create_package() # set up testing in rstudio package usethis::use_testthat() # create a context file usethis::use_test() # add context to first line of context file context("what these tests test")
quack <- function(says_the_duck = "quack!", greeting = "quack! ") { paste0(greeting, says_the_duck, " said the duck") }
quack()
## [1] "quack! quack! said the duck"
quack("quack, quack!")
## [1] "quack! quack, quack! said the duck"
context("test that the duck quacks") library(stringr) expect_neet_quack <- function(quack_output) { expect_gte( str_length(quack_output), 1) expect_type(quack_output, "character") } test_that("duck quacks", { expect_neet_quack(quack()) expect_neet_quack( quack("quack, quack!")) })
context("nas nans infs in confidence scores") method_nans <- function(method_to_test) { cs <- expert_judgements_frankenstein %>% method_to_test() %>% purrr::pluck("cs") expect_false(NA %in% cs) expect_false(NaN %in% cs) expect_false(Inf %in% cs) expect_false(-Inf %in% cs) expect_false(any(cs < 0)) expect_false(any(cs > 1)) expect_false(any(cs == 0)) expect_false(any(cs == 1)) expect_is(cs, "numeric") }
## Set panda = 68 to reproduce this panda.
## Set panda = 58 to reproduce this panda.
Gray, Charles T. 2019. “Code::Proof: Prepare for Most Weather Conditions.” In Statistics and Data Science, edited by Hien Nguyen, 22–41. Communications in Computer and Information Science (Preprint: Https://Arxiv.org/1910.06964.pdf). Singapore: Springer. https://doi.org/10.1007/978-981-15-1960-4_2.
Wickham, H. 2015. R Packages: Organize, Test, Document, and Share Your Code. O’Reilly Media.
Wickham, Hadley. 2011. “Testthat: Get Started with Testing.”
Wickham, Hadley, and Jennifer Bryan. 2019. “Usethis: Automate Package and Project Setup.”