5

I am using testthat to write tests for my R package. One of my tests makes use of jitter. I want to make sure the test is reproducible.

Do I put set.seed(1014)

  1. Before or after library(testthat) in ./tests/testthat.R; or
  2. At the top of each test file (before or after context("Test) in ./tests/testthat/test-function.R; or
  3. At the top of each unit test (inside of test_that("Example works"){jitter(1)})) in ./tests/testthat/test-function.R?

And why?

robust
  • 594
  • 5
  • 17
  • 2
    Well, if you don't want your tests to depend on the order in which they are run, you should set the seed as close to where you are going to be selecting random numbers. So I suggest putting it inside the unit test itself. – MrFlick May 17 '19 at 18:40

1 Answers1

7

If you only declare set.seed() once, then you always need to run the tests that use randomness in the same order in order to get the same results. However, it's probably not a good idea for unit test to only work when run in a certain order. You should set the seed as close to the time that you need to verify a random value is returned.

Here's a function that can set the seed for just a code block

with_seed <- function(seed, code) {
  code <- substitute(code)
  orig.seed <- .Random.seed
  on.exit(.Random.seed <<- orig.seed)
  set.seed(seed)
  eval.parent(code)
}

You can run it like

with_seed(5, rnorm(5))

or

with_seed(5, {
  a <- rnorm(5)
  b <- runif(5)
  a + b
})

But you will still get random numbers for the original seed outside the block.

If you would prefer to pull such a function from an existing package, the withr::set_seed appears to do the same thing.

MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • Thank you for your answer! Any advice on where to put `with_seed`? :) – robust May 17 '19 at 20:10
  • 2
    You could probably add that as a helper function: https://stackoverflow.com/questions/35941729/r-testthat-unit-test-data-and-helper-function-conventions – MrFlick May 17 '19 at 20:37