ALL Metrics
-
Views
Get PDF
Get XML
Cite
Export
Track
Software Tool Article
Revised

exampletestr—An easy start to unit testing R packages

[version 2; peer review: 2 approved]
Previously titled: Easier unit tests and better examples with exampletestr and covr
Rory Nolan1Sergi Padilla-Parra1,2
Rory Nolan1Sergi Padilla-Parra1,2
PUBLISHED 21 Jun 2017
Author details Author details
OPEN PEER REVIEW
REVIEWER STATUS

Abstract

In spite of the utility of unit tests, most R package developers do not write them. exampletestr makes it easier to start writing unit tests by creating shells/skeletons of unit tests based on the examples in the user's package documentation. When completed, these unit tests test whether said examples run correctly. By combining the functionality of exampletestr with that of covr, having ensured that their examples adequately demonstrate the features of their package, the developer can have much of the work of constructing a comprehensive set of unit tests done for them.

Keywords

R, unit, test, testing, testthat, covr, exampletestr

Revised Amendments from Version 1

This version (2) makes revisions suggested by reviewer Laurent Gatto. The introduction now provides the rationale for unit testing. A discussion is included to stress the point that the type of tests that exampletestr can help you with are not the only type of test that a package should have. It is made clear that retrospective testing (which is what exampletestr is useful for) is not necessarily the best way to test a package.

See the authors' detailed response to the review by Thomas Quinn
See the authors' detailed response to the review by Laurent Gatto

Introduction

Unit tests are automated checks which examine whether a package works as intended. There are many reasons to write unit tests:

  • 1. To identify bugs in your current code. If a test fails, something is not working as expected.

  • 2. To make current package functionality robust to future changes. If you have written good tests, you do not need to worry that changes made to your code have broken existing functionality; the tests will tell you whether or not the original functionality is in tact. In the words of Hadley Wickham, "I started using automated tests because I discovered I was spending too much time refixing bugs that I’d already fixed before."1

  • 3. Test-driven development (TDD). Some people advocate writing tests before writing code: the tests outline what your code should do and you know your code is working correctly when the tests start passing. The use of TDD achieves the quality control goals of points 1 and 2 above as code is written. This contrasts with retrospective unit testing, which is to write unit tests after everything else is done.

  • 4. To assure others that your code works correctly. The fact that a package is unit tested indicates to potential users that the author has taken care to ensure that their code works as intended.

For the above reasons, it is good practice to write unit tests for R packages. However, at the time of writing, of the 10084 packages on CRAN, only 25% (2566) are unit tested. Of the 5715 packages authored or updated since 1st January 2016, 35% (1984) are unit tested. Hence, the majority of packages on CRAN are not unit tested. Testing for these packages would have to be done retrospectively.

This paper describes exampletestr, a package that makes it easy for package developers to retrospectively create unit tests based on the examples in their package documentation. exampletestr is designed for developers who have a functioning package that they would like to unit test; it is less useful for those using TDD.

Methods

Implementation

exampletestr is designed for tests to be written within the testthat2 framework. This is the most popular testing framework, preferred in 93% of cases. exampletestr works by reading the examples in the .Rd files in the man/ folder of the package project. These examples are then wrapped in test_that and expect_equal statements, thereby creating test shells.

By running make_tests_shells_pkg() in the root directory of a package, for each x.R file in the R/ directory that has at least one function documented with an example, you get a corresponding file test_x.R in the tests/testthat/ directory of the package, containing these test shells to be filled in by the user (a package developer) to create fully functional unit tests.

For a complete overview of exampletestr’s capabilities, consult the package’s manual and vignette at https://CRAN.R-project.org/package=exampletestr.

Operation

This package can be used with R version 3.3.0 or later on Linux, Mac and Windows. It can be installed from within R via the command install.packages("exampletestr").

The idea of basing unit tests around documentation examples suggests the use of covr3 in the following way to ensure both that the examples in the documentation exhibit as much of the functionality of the package as possible and that the unit tests cover as much of the code as feasible:

  • 1. Write comprehensive documentation examples for your package, using covr’s package_coverage(type = "examples") %>% shine() to ensure that all sections of code that the package user may find useful are demonstrated.

  • 2. Write unit tests corresponding to all of your examples using exampletestr.

  • 3. Complete the writing of unit tests, checking your code coverage with package_coverage(type = "tests") %>% shine().

  • Using this workflow, the developer ensures that their example coverage (the portion of package features covered by documentation examples) is adequate, and simultaneously obtains a reduction in the work required to write comprehensive unit tests.

Use cases

The best way to display the functionality of exampletestr is by example. Take the str_detect function from the stringr package4. The main file str_detect.Rd has the examples section:

\examples{
fruit <- c("apple", "banana", "pear", "pinapple")
str_detect(fruit, "a")
str_detect(fruit, "^a")
str_detect(fruit, "a$")
str_detect(fruit, "b")
str_detect(fruit, "[aeiou]")
# Also vectorised over pattern
str_detect("aecfg", letters)
}

The test shell that would be automatically created by exampletestr from these examples is:

test_that("str_detect works", {
  fruit <- c("apple", "banana", "pear", "pinapple")
  expect_equal(str_detect(fruit, "a"), )
  expect_equal(str_detect(fruit, "^a"), )
  expect_equal(str_detect(fruit, "a$"), )
  expect_equal(str_detect(fruit, "b"), )
  expect_equal(str_detect(fruit, "[aeiou]"), )
  expect_equal(str_detect("aecfg", letters), )
})

which can then be filled in by the package developer to give the complete and passing test:

test_that("str_detect works", {
  fruit <- c("apple", "banana", "pear", "pinapple")
  expect_equal(str_detect(fruit, "a"), rep(TRUE, 4))
  expect_equal(str_detect(fruit, "^a"), c(TRUE, rep(FALSE, 3)))
  expect_equal(str_detect(fruit, "a$"), c(FALSE, TRUE, FALSE, FALSE))
  expect_equal(str_detect(fruit, "b"), c(FALSE, TRUE, FALSE, FALSE))
  expect_equal(str_detect(fruit, "[aeiou]"), rep(TRUE, 4))
  expect_equal(str_detect("aecfg", letters), 
                c(TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, rep(FALSE, 19)))
})

Discussion

Testing whether documentation examples run correctly (which is what exampletestr is useful for) is just one important part of writing good unit tests. Two points to bear in mind when using exampletestr:

  • 1. Documentation examples typically showcase a best case application of the code in a package. Unit testing should go beyond this and assess the execution of edge cases, e.g. the performance of functions when an argument is empty (length zero). exampletestr does not help in this regard.

  • 2. exampletestr promotes a “one test per function” model. However, in many packages, it is necessary to go further than just testing whether each function performs well in isolation. For instance, it is good to test function composition: whether one obtains the expected results when applying two or more functions, one after another.

Conclusions

Unit tests are crucial to ensuring that a package functions correctly, yet most developers do not write them. Most package developers do, however, write documentation examples. With exampletestr, documentation examples are easily transformed into unit tests; thereby encouraging maintainers of untested packages to make a start on unit testing.

Software and data availability

exampletestr can be downloaded from: https://CRAN.R-project.org/package=exampletestr

Source code available from: https://github.com/rorynolan/exampletestr

Archived source code as at time of publication: DOI: 10.5281/zenodo.575664

Software license: GPL-3

The data presented can be found at https://github.com/rorynolan/exampletestr/tree/master/analysis, along with a file showing how to reproduce that data.

Looking for the Open Peer Review Reports?

They can now be found at the top of the panel on the right, linked from the box entitled Open Peer Review. Choose the reviewer report you wish to read and click the 'read' link. You can also read all the peer review reports by downloading the PDF.

Comments on this article Comments (0)

Version 2
VERSION 2 PUBLISHED 17 May 2017
Comment
Author details Author details
Copyright
Download
 
Export To
metrics
Views Downloads
Wellcome Open Research - -
Data from PMC are received and updated monthly.
- -
Citations
CITE
how to cite this article
Nolan R and Padilla-Parra S. exampletestr—An easy start to unit testing R packages [version 2; peer review: 2 approved] Wellcome Open Res 2017, 2:31 (https://doi.org/10.12688/wellcomeopenres.11635.2)
NOTE: it is important to ensure the information in square brackets after the title is included in all citations of this article.
track
receive updates on this article
Track an article to receive email alerts on any updates to this article.

Open Peer Review

Current Reviewer Status: ?
Key to Reviewer Statuses VIEW
ApprovedThe paper is scientifically sound in its current form and only minor, if any, improvements are suggested
Approved with reservations A number of small changes, sometimes more significant revisions are required to address specific details and improve the papers academic merit.
Not approvedFundamental flaws in the paper seriously undermine the findings and conclusions
Version 2
VERSION 2
PUBLISHED 21 Jun 2017
Revised
Views
0
Cite
Reviewer Report 29 Jun 2017
Laurent Gatto, Computational Proteomics Unit, University of Cambridge, Cambridge, UK 
Approved
VIEWS 0
Thank you for the amendments, Rory. ... Continue reading
CITE
CITE
HOW TO CITE THIS REPORT
Gatto L. Reviewer Report For: exampletestr—An easy start to unit testing R packages [version 2; peer review: 2 approved]. Wellcome Open Res 2017, 2:31 (https://doi.org/10.21956/wellcomeopenres.12933.r23685)
NOTE: it is important to ensure the information in square brackets after the title is included in all citations of this article.
Version 1
VERSION 1
PUBLISHED 17 May 2017
Views
0
Cite
Reviewer Report 12 Jun 2017
Laurent Gatto, Computational Proteomics Unit, University of Cambridge, Cambridge, UK 
Approved with Reservations
VIEWS 0
The manuscript Easier unit tests and better examples with exampletestr and covr describes the `exampletestr` package that parses the example code in the manual pages and converts it into unit test stubs to be then completed by the developer.
... Continue reading
CITE
CITE
HOW TO CITE THIS REPORT
Gatto L. Reviewer Report For: exampletestr—An easy start to unit testing R packages [version 2; peer review: 2 approved]. Wellcome Open Res 2017, 2:31 (https://doi.org/10.21956/wellcomeopenres.12567.r23062)
NOTE: it is important to ensure the information in square brackets after the title is included in all citations of this article.
  • Author Response 13 Jun 2017
    Rory Nolan
    13 Jun 2017
    Author Response
    Hi Laurent,
    Thanks for the review and advice. I agree on all points and I'll edit the manuscript accordingly. I'll submit my revisions within the next 2 weeks. 
    For now, ... Continue reading
  • Author Response 21 Jun 2017
    Rory Nolan
    21 Jun 2017
    Author Response
    Dear Laurent,
    I have submitted a new version of the manuscript. I hereby outline my response to your comments.

    I think it would be useful for the authors to ... Continue reading
COMMENTS ON THIS REPORT
  • Author Response 13 Jun 2017
    Rory Nolan
    13 Jun 2017
    Author Response
    Hi Laurent,
    Thanks for the review and advice. I agree on all points and I'll edit the manuscript accordingly. I'll submit my revisions within the next 2 weeks. 
    For now, ... Continue reading
  • Author Response 21 Jun 2017
    Rory Nolan
    21 Jun 2017
    Author Response
    Dear Laurent,
    I have submitted a new version of the manuscript. I hereby outline my response to your comments.

    I think it would be useful for the authors to ... Continue reading
Views
0
Cite
Reviewer Report 30 May 2017
Thomas Quinn, Bioinformatics Core Research Group, Deakin University, Geelong, Vic, Australia 
Approved
VIEWS 0
The authors clearly outline the importance of unit testing. They then introduce a new package aimed to make it easier for developers to add unit tests to their own package. They do this by drawing from examples provided in the ... Continue reading
CITE
CITE
HOW TO CITE THIS REPORT
Quinn T. Reviewer Report For: exampletestr—An easy start to unit testing R packages [version 2; peer review: 2 approved]. Wellcome Open Res 2017, 2:31 (https://doi.org/10.21956/wellcomeopenres.12567.r22849)
NOTE: it is important to ensure the information in square brackets after the title is included in all citations of this article.
  • Author Response 21 Jun 2017
    Rory Nolan
    21 Jun 2017
    Author Response
    Dear Thomas,
    I have submitted a revised version of the article to address Laurent Gatto's review.
    This new version puts the package into better context.
    The package has been updated ... Continue reading
COMMENTS ON THIS REPORT
  • Author Response 21 Jun 2017
    Rory Nolan
    21 Jun 2017
    Author Response
    Dear Thomas,
    I have submitted a revised version of the article to address Laurent Gatto's review.
    This new version puts the package into better context.
    The package has been updated ... Continue reading

Comments on this article Comments (0)

Version 2
VERSION 2 PUBLISHED 17 May 2017
Comment
Alongside their report, reviewers assign a status to the article:
Approved - the paper is scientifically sound in its current form and only minor, if any, improvements are suggested
Approved with reservations - A number of small changes, sometimes more significant revisions are required to address specific details and improve the papers academic merit.
Not approved - fundamental flaws in the paper seriously undermine the findings and conclusions

Are you a Wellcome-funded researcher?

If you are a previous or current Wellcome grant holder, sign up for information about developments, publishing and publications from Wellcome Open Research.

You must provide your first name
You must provide your last name
You must provide a valid email address
You must provide an institution.

Thank you!

We'll keep you updated on any major new updates to Wellcome Open Research

Sign In
If you've forgotten your password, please enter your email address below and we'll send you instructions on how to reset your password.

The email address should be the one you originally registered with F1000.

Email address not valid, please try again

You registered with F1000 via Google, so we cannot reset your password.

To sign in, please click here.

If you still need help with your Google account password, please click here.

You registered with F1000 via Facebook, so we cannot reset your password.

To sign in, please click here.

If you still need help with your Facebook account password, please click here.

Code not correct, please try again
Email us for further assistance.
Server error, please try again.