R package for extending testthat to more testing helpers
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
R
inst/images
man
tests
.Rbuildignore
.gitignore
.travis.yml
DESCRIPTION
LICENSE
NAMESPACE
NEWS.md
README.md

README.md

Extended Testing Framework for R Build Status Coverage Status

Hadley's testthat revolutionized package development in the R-sphere, but there are still some features lacking. testthatsomemore provides:

  • The ability to mock and stub functions and closures, including those in packages.
  • Creation of hierarchical file structures for testing of IO-related functions.
  • Pretending now is some other time, like Ruby's Timecop gem.
  • Indicating that some tests are pending.

To use, simply run install.packages("testthatsomemore") (for the latest stable version 0.2.4, uploaded to CRAN on October 10, 2015), or the below code to install the latest development version:

if (!require(testthatsomemore)) {
  if (!require(devtools)) install.packages('devtools'); require(devtools)
  install_github('robertzk/testthatsomemore') 
}

Explicitly load library(testthatsomemore) before running unit tests with devtools::test.

Examples

Stubbing

To test certain functions in your package it may be required to "stub" away some of the functionality to avoid unnecessary action. For example, when testing a function that trains an algorithm over an extended period of time, it would be helpful to skip the computationally expensive step and ensure the rest of the code is working as expected. We can use testthatsomemore in our tests as follows. Imagine we have a function as below.

complicated_function <- function() {
  input <- something_simple()
  output <- something_long_and_complicated(input)
  something_else_simple(output)
}

We can then "stub" away the long and complicated sub-function so it won't actually execute.

context('your function')

test_that("it does what it's supposed to do", {
  stub(complicated_function, "something_long_and_complicated") <- function(...) "test"
  expect_identical(complicated_function(), something_else_simple("test"))
})

Mocking file structures

On other occasions, your R package may expect certain files to be present on the file system. For example, imagine you are writing a package that processes batch jobs by moving files in a folder called "available" to a folder called "completed". These jobs are represented in some simple text format. You could then test your package as follows.

test_that('it can perform a simple job', {
  within_file_structure(list(available = list(job1 = "some\nfile\ncontents")), {
    # `tempdir` is a special local variable that holds our directory
    # created on the fly for this test. When we get to the end of the test,
    # this directory will be deleted.
    perform_job(dir = tempdir, name = "job1")

    # expect_is_file is another testthatsomemore helper
    expect_is_file(file.path(tempdir, "completed", "job1"))
  })
})

Stubbing functions in packages

Sometimes, it may be very difficult to stub away a certain method because you do not own it (e.g., it is in another package). In this case, you can use the package_stub function.

test_that('it can stub away stats::lm!', {
  package_stub("stats", "lm", function(...) "I'm a model", {
    # Within the confines of these braces, lm is temporarily
    # a stubbed function. It will be restored when this test is over.
    expect_identical(lm(Sepal.Width ~ Sepal.Height, iris), "I'm a model")
  })
})

Pretend now is some other time

For some tests, we may want to temporarily stub the current timestamp to be something else. For example, if we would like to test that our package can store the last time it has given the user a helpful tip, and only re-show that tip once every month, we could use the pretend_now_is helper function.

expect_output(show_tip(), "helpful tip") # Or some message you wrote.
expect_output(show_tip(), "") # No output the second time! Too soon.
pretend_now_is("2 months from now", {
  # We can use English. Any combination of <number> <time>s <from now/ago>
  # will work, e.g., "5 seconds from now", "3 months ago", etc.
  expect_output(show_tip(), "helpful tip")
})

Mocking httr response

We want to be able to mock http GET and PUT response objects when testing. For this purpose, you can use mock_httr_response to create an httr object.

describe("mocking httr GET", {
  with_mock(
    `httr::GET` = function(...) mock_httr_response(200L, list(data = "my data!"), "json"),
    test_that("my test", {
      ...
      ...
  })
})

Pending

Keeping in line with test-driven development, we should be able to denote that a test is "pending" completion. If you use testthat with the default reporter (think lines of green dots), the pending function will display a yellow dot to indicate it must still be implemented.

test_that('i have to write this test', {
  pending()
})

pending

               ^ pending