Unit Testing in R

NHS R Conference 2023

Priyanka Gagneja

Oct 10,2023

Introduction


Priyanka Gagneja
Lead Analyst at OnPoint Insights

Big Fan of R community

Agenda

  • Why
  • When
  • What
  • Demo

What is Testing ?



  • Ensure your code does,
  • what you think it does,
  • at all times.



Types of Testing ?

  • Unit testing:
    • Is each of your units working as expected individually ?
  • Regression testing:
    • After you have modified your code base (i.e. a bug fix), is your code still returning the same expected results?
  • Integration testing:
    • Is your code talking with other components, i.e. log servers or databases?
  • Load testing:
    • Is your code working under load, i.e. when many users are running it?
  • Performance testing:
    • Is your code fast enough?
  • Penetration testing:
    • How secure is your code against malicious attempts to run it?

What is a Unit in R ?





A function

Why we need Unit Testing ?




Robust



In a growing codebase, you will need unit tests. Sometimes even small scripts can sometimes produce a lot of distress.

– André Müller

When should we Test ?

The three right answers are:

  • ALWAYS!
  • EARLY!
  • OFTEN!

“A software system can best be designed if the testing is interlaced with the designing instead of being used after the design”

– Alan Perlis, NATO Software Engineering Conference, 1968 (source https://www.infoq.com/presentations/1-9-6-8)

What should we Test ?



Test the behaviour of your unit, not its implementation



Typical Coding Workflow



  • Write a function.
  • Experiment with it in the console to see if it works.
  • Rinse and repeat.

Demo - Typical Coding Workflow

# Write a function
rescale <- function(x, r.out) {
  p <- (x - min(x)) / (max(x) - min(x))
  r.out[[1]] + p * (r.out[[2]] - r.out[[1]])
}

Demo - Typical Coding Workflow

# Write a function
rescale <- function(x, r.out) {
  p <- (x - min(x)) / (max(x) - min(x))
  r.out[[1]] + p * (r.out[[2]] - r.out[[1]])
}

# Experiment 
x <- rnorm(20)
r.out <- c(0.1, 1.4)
range(rescale(x, r.out)) == r.out
[1] TRUE TRUE

How to do Unit Testing ?

 

testthat package

Demo - testthat

library(testthat)

# Write a function
rescale <- function(x, r.out) {
  p <- (x - min(x)) / (max(x) - min(x))
  r.out[[1]] + p * (r.out[[2]] - r.out[[1]])
}

# Experiment 

# x <- rnorm(20)
# r.out <- c(0.1, 1.4)
# range(rescale(x, r.out)) == r.out

Demo - testthat

library(testthat)

# Write a function
rescale <- function(x, r.out) {
  p <- (x - min(x)) / (max(x) - min(x))
  r.out[[1]] + p * (r.out[[2]] - r.out[[1]])
}

# Experiment 

# x <- rnorm(20)
# r.out <- c(0.1, 1.4)
# range(rescale(x, r.out)) == r.out

# Write a formal unit test
testthat::expect_that(range(rescale(x, r.out)), equals(r.out))

# testthat::expect_equal(range(rescale(x, r.out)), r.out)

How to automate Testing ?

  • The easiest way to get started is with usethis.

  • Assuming you’re in project directory, run usethis::use_test("function-name") , e.g usethis::use_test("rescale") to create a test file, and set up all the other infrastructure you need.

  • Run tests in a single file - test_file(path = "./tests/testthat/test-rescale.R")

  • If you’re using RStudio, press Cmd/Ctrl + Shift + T (or run devtools::test() if not) to run all the tests in a package.

Why testing is important?

  • Seems like extra work but will save you time * Decreased frustration. Bugs appear very close to hard deadlines. Testing allows to quickly identify where the problem is and fix it.

  • More confidence in the code * Better code structure. Code that is easy to test is usually better designed. Tests sometimes make you see large complicated functions and break them down into smaller, more manageable chunks.

  • Make changes or updates without worrying too much * Make changes confidently because you know your tests will catch any issues.

References/Acknowledgements

  • https://testthat.r-lib.org/
  • https://r-pkgs.org/testing-basics.html
  • https://towardsdatascience.com/unit-testing-in-r-68ab9cc8d211
  • https://medium.com/@adrian.joseph/everything-you-want-to-know-about-unit-testing-in-r-part-1-6f76a4d5748a
  • https://resbaz.github.io/2014-r-materials/lessons/45-testing/
  • https://r-pkgs.org/tests.html
  • https://testthat.r-lib.org/reference/test_package.html#special-files

Thank You