3/21/2019
Validate software actions.
Validate software performance.
A unit test is a method that instantiates a small portion of our application and verifies its behavior independently from other parts.
library(testthat) my_sum <- function(...) { numbers <- list(...) total = 0 for (number in numbers){ total = total + number } return(total) } testthat::test_that("`sum` adds numbers like it should...", { testthat::expect_true(my_sum(1, 2, 3) == 6) })
import unittest def sum(arg): total = 0 for val in arg: total += val return total class TestSum(unittest.TestCase): def test_list_int(self): data = [1, 2, 3] result = sum(data) self.assertEqual(result, 6) if __name__ == '__main__': unittest.main()
Test Driven Development (TDD) is a development and testing practice characterized by a set of steps:
a.k.a. “Red – Green – Refactor”.
# bad, the first failure prevents the evaluation of the next assertion testthat::test_that("Check multiple things", { testthat::expect_true(my_sum(1, 2, 3) == 6) testthat::expect_true(my_sum(NA, NULL, 3) == 3) }) # good, independent assertions let us hone in on the problem testthat::test_that("Check one thing", { testthat::expect_true(my_sum(1, 2, 3) == 6) }) testthat::test_that("Check the other thing", { testthat::expect_true(my_sum(NA, NULL, 3) == 3) })
absolute_value = function(x) { if (x < 0) { x = -x } return(x) }
Find your edge cases, test on both sides…
testthat::expect_true("Check behavior at zero", { testthat::expect_true(absolute_value(0) == 0) }) testthat::expect_true("Check behavior below zero", { input <- -0.000000001 testthat::expect_true(absolute_value(input) == -input) }) testthat::expect_true("Check behavior above zero", { input <- 0.000000001 testthat::expect_true(absolute_value(input) == input) })
“Expected behavior” shouldn’t be limited to the positive use-case. Consider the following scenario where we have added additional checks on our function inputs:
absolute_value = function(x){ if (is.null(x) || is.na(x)){ stop("x must not be NULL, or NA.") } if (!is.numeric(x)) { stop("x must be numeric") } if (x < 0) { x = -x } return(x) }
full
test coverage?testthat::test_that("Check behavior NA", { testthat::expect_error(absolute_value(NA)) }) testthat::test_that("Check behavior NULL", { testthat::expect_error(absolute_value(NULL)) }) testthat::test_that("Check behavior NULL", { testthat::expect_error(absolute_value("12")) })