Search code examples
runit-testingtestthat

How can I mock a function globally using testthat?


I have a function which is being called in multiple functions. All of them sit in separate files. Let's take an example to understand it.

# R/generic_function.R
generic_function <- function() {
....
....
}

# R/functionA.R
function_A <- function() {
...
generic_function()
...
}

# R/functionB.R
function_B <- function() {
...
generic_function()
...
}

I am writing tests for them using testthat in corresponding test files where I am mocking the generic_function()

# tests/testthat/test-functionA.R
mockery::stub(function_A, "generic_function", TRUE)
...
...


# tests/testthat/test-functionB.R
mockery::stub(function_B, "generic_function", TRUE)
...
....

There are too many such function* files and corresponding test-function* files. I am wondering if there is a way where I can mock such files on global level only once?


Solution

  • I solved it using setup.R and teardown.R files. These files are special and have a some special characteristics.

    setup.R file is ran before every test file. In setup.R we replace generic_function with mock_generic_function in global environment.

    # tests/testthat/setup.R
    mock_generic_function <- function(...) {
      TRUE
    }
    message("Running setup.R before the test...")
    assign("generic_function ", mock_generic_function , envir = globalenv())
    

    teardown.R is ran after all the tests are run where we remove the (mocked) generic_function from global environment.

    rm(generic_function, envir = globalenv())
    message("Running teardown.R after the tests have been executed...")
    

    PS - From the help file, the usage of setup and teardown is superseded however, this approach works well for me so I am using this for time being.