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"))
})