Spring 2023
Smith College
To learn about and create automated tests for your package.
Code to assure
the output you are getting
is the output you expect.
We are testing constantly while writing new code.
Often we write a line, try it, get an error, adapt, and try again.
This works great while you are working on something new.
Recall this loops forever …
Yet this is fine…
You’ve (hopefully) also tested your package functions along the way.
This requires a few extra steps, but the process is the same.
Try, revise, try again …
Making Package Functions:
You’re only doing them now.
What happens when you change something later? Will you come back and make sure everything still works?
Say you create a function for your package that you will use as an intermediate step …
Week 1
[1] "a" "d" "g" "i" "l" "o" "q" "t" "w" "y"
Week 6
[1] "A" "D" "G" "I" "L" "O" "Q" "T" "W" "Y"
Even simple tests can prevent heartache.
A simple test for our above example would be something like: “If all of my results are false, I should probably look into that.”
We can code these gut checks into actual tests that will be run whenever we check our package.
tests
is an “optional” directory which contains unit-tests for your code.
Unit tests essentially run your code and check the results against pre-determined outputs.
If you change something and one of these known outputs change, you know something broke.
R Project Name
.
├── R/
│ └── func1.R
├── man/
│ └── func1.Rd
├── inst/
│ ├── data/
│ │ └── example_data1.csv
│ └── other
├── vignettes/
│ └── v1.rmd
├── docs/
│ └── v1.html
├── tests/
│ └── testthat/
│ └── test-func1.R
├── NAMESPACE
├── DESCRIPTION
├── LICENSE
├── NEWS.md
├── README.Rmd
├── .gitignore
└── .Rbuildignore
testthat
PackageThe testthat
package integrates testing into the process of building your package.
Much like how roxygen2
gives us helpers for documentation, testthat
gives us helpers for tests.
You can use usethis::use_test()
to create a test file for the currently open function.
If I have the R/comma_split.R
function open, I can use usethis::use_test()
to create a test template.
✔ Setting active project to 'final-project-test-team'
✔ Adding 'testthat' to Suggests field in DESCRIPTION
✔ Setting Config/testthat/edition field in DESCRIPTION to '3'
✔ Creating 'tests/testthat/'
✔ Writing 'tests/testthat.R'
✔ Writing 'tests/testthat/test-comma_split.R'
• Modify 'tests/testthat/test-comma_split.R'
This creates a matching tests/testthat/test-comma_split.R
file.
Much like help files, we have tools to scaffold for us, but we still need to build things ourselves.
Tests are just R code, but makes use of some specific functions.
Each of these functions is designed to compare the results of some code with a known answer.
Some tests you can run:
expect_equal()
expect_error()
expect_warning()
expect_message()
expect_s3_class()
expect_true()
expect_false()
testthat
# assuming my_func_2 is in package
out = my_func_2(out_1)
# test
testthat::test_that("Is my_func_2 working?", {
# I expect at least 1 true
testthat::expect_true(any(out))
})
── Failure ('<text>:8'): Is my_func_2 working? ─────────────────────────────────
any(out) is not TRUE
`actual`: FALSE
`expected`: TRUE
Error in `reporter$stop_if_needed()`:
! Test failed
Note that when writing tests for a package, you don’t need testthat::
for everything. R will load it when it goes to test things.
Your tests will now run every time you use devtools::test()
or devtools::check()
your package.
Most of the time, things will work fine!
However, if anything ever does break, you will have an early warning, and clear hints on where and why things broke.
Much like examples, tests need to be simple, yet realistic
They must also be completely self-contained.
They do have access to and data you store in inst/data
though.
Tests should:
Your go-to tool for checking up on how your package is working is the devtools::check()
function.
It will run all of your tests, and check some other basic milestones and see if your package is healthy.
You should check often to make sure you aren’t accumulating problems.
If you have been using the package::function()
syntax in your functions (as you should be doing), you will get an error when you now run devtools::check()
This is because we have not added those packages to the dependancies for our package yet.
To do so, simply run usethis::use_package("PACKAGE NAME")
. This will add it to your description file.
Benchmarking
SDS 270: Advanced Programming for Data Science