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.
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:
Inner()
are by design not public (they're not exported in NAMESPACE
) we shouldn't even be trying to test them.testthat
package wiki says it supports testing of "non-exported functions" using an R CMD check
workflow.Outer()
functions for testing purposesSolution 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.
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!
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With