Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can we test functions that aren't exposed when building R packages?

I'm currently developing a graphical analysis package for R. We're trying to use principles from both Clean Code and Test-Driven Development (TDD). But, we've run into a conceptual problem.

How can you test unexposed functions?

Consider the following simplified example. Outer() is a function we're building in our package, and we expose it to users by listing it in the NAMESPACE file. Inner() is a short (~5 line) utility function:

Outer <- function(...) {

  Inner <- function(...) {
    return(x)
  }

  return( Inner() )
}

Most of the user-exposed functions in our package are collections of short, single-behavior Inner() style functions that lie under the umbrella of a single Outer() function the user can call. Granova.ds.ggplot() is one example. Such a modular design is strongly advocated by Clean Code, and we're quite happy with the results. But we don't know how to build unit tests for it, since the functions we want to test aren't accessible outside the scope of the Granova.ds.ggplot() function given how we designed it.

Several ideas/solutions occurred to us:

  1. Tests should only have access to public APIs. Since functions like Inner() are by design not public (they're not exported in NAMESPACE) we shouldn't even be trying to test them.
  2. Hadley Wickham's testthat package wiki says it supports testing of "non-exported functions" using an R CMD check workflow.
  3. If all else fails, we could somehow manually break our Outer() functions for testing purposes

None of these solutions has worked so far

Solution 1 seems like a cop-out. We believe that especially in R, it's sensible to have a top-level function that calls various short, single-responsibility utility methods. Not being able to test such methods seems silly, and like the type of thing there's a solution for but we just haven't found yet.

Solution 2 might work, but we haven't gotten it to work so far. If you try cloning our repository, then sourcing inst/dev.R I believe you'll find in the test output that it cannot find the function InitializeGgplot(), even though said function is defined in lines 613-615 of granova.1w.ggplot(). Similarly, running R CMD check at the terminal doesn't seem to execute any of our tests at all. It does take a great deal of time and throw insulting errors at us, though :-(

Solution 3 is in a sense pragmatic, but counter to the aim of always moving toward a goal state of the project. It doesn't make sense to us.

What would be the ideal solution

Ideally, we're looking for a way to leverage a package like testthat to rapidly provide feedback as we code, and to allow us to test functions like Inner() that exist within functions like Outer(). Even better would be a way to do it without resorting to R CMD check, which due to the 3-d complexity of some of our functions takes almost a full minute to run each time.

So, what are we missing? Should TDD practices allow for testing Outer/Inner style setups in R? If they do, how can we do so in developing our package? Any feedback is welcome, and I'll try to respond to anything that's unclear.

Thanks!

like image 907
briandk Avatar asked May 18 '11 07:05

briandk


People also ask

How do I test a package in R?

Assuming you're in a package directory, just run usethis::use_test("name") to create a test file, and set up all the other infrastructure you need. If you're using RStudio, press Cmd/Ctrl + Shift + T (or run devtools::test() if not) to run all the tests in a package.

How do I test an R script?

A test R script should start with the prefix 'test-'. A good way of doing this is to add the prefix to the name of file that stores the functions to be tested. In other words, if you are testing the functions in the file temp_conversion. R, then you can save the tests in the file test-temp_conversion.

Which package is used in testing of R code?

In R programming testthat package helps us to implement unit testing in our codes. To install testthat package one just need to run the following code in his R console. testthat uses test_that() function to create a test and uses expectations for unit testing of code.

What is test function R?

T-tests in R is one of the most common tests in statistics. So, we use it to determine whether the means of two groups are equal to each other. The assumption for the test is that both groups are sampled from normal distributions with equal variances.


1 Answers

If Inner implements non-trivial functionality that you want to test, I'd suggest moving Inner to the top-level, but not exporting it. Generally, I avoid nesting functions within other functions for exactly this reason - they're hard to test.

You can test during development with the usual testthat functions because you're probably just sourcing in all your R code and not worrying about namespaces (at least that's how I develop). You then use R CMD check in conjunction with test_package to ensure the tests still work at build time - test_packages runs the tests in the package namespace so they can test non-exported functions.

like image 62
hadley Avatar answered Sep 19 '22 17:09

hadley