Skip to contents

Documentation examples and tests are similar in some ways:

  • They are self-contained pieces of code.

  • They should cover the software’s most important functions and typical uses.

  • They should be simple and clear: complex examples are hard for users to understand, and complex test code can introduce testing bugs.

This similarity makes it attractive to use “doctests”, which combine tests and documentation. Indeed, several languages, including Python and Rust, have doctests built in.[1] R also checks for errors in examples when running R CMD check.

The doctest package extends this idea. It lets you write testthat tests, by adding tags to your roxygen documentation. This helps you check that your examples do what they are supposed to do.

Example

Here’s some roxygen documentation for a function:


#' Fibonacci function 
#' 
#' @param n Integer
#' @return The nth Fibonacci number
#' 
#' @doctest
#'
#' @expect type("integer")
#' fib(2)
#'
#' n <- 6 
#' @expect equal(8)
#' fib(n)
#' 
#' @expect warning("not numeric")
#' fib("a")
#'
#' @expect warning("NA")
#' fib(NA)
fib <- function (n) {
  if (! is.numeric(n)) warning("n is not numeric")
  ...
}

Instead of an @examples section, we have a @doctest section.

This will create tests like:

# Generated by doctest: do not edit by hand
# Please edit file in R/<text>

test_that("Doctest: fib", {
  # Created from @doctest for `fib`
  # Source file: <text>
  # Source line: 7
  expect_type(fib(2), "integer")
  n <- 6
  expect_equal(fib(n), 8)
  expect_warning(fib("a"), "not numeric")
  expect_warning(fib(NA), "NA")
})

The .Rd file will be created as normal, with an example section like:

\examples{
fib(2)

n <- 6 
fib(n)
fib("a")
fib(NA)
}

Usage

Install doctest from r-universe:

install.packages("doctest", repos = c("https://hughjonesd.r-universe.dev", 
                                      "https://cloud.r-project.org"))

Or from CRAN:

install.packages("doctest")

Or get the development version:

devtools::install("hughjonesd/doctest")

To use doctest in your package, alter its DESCRIPTION file to add the dt_roclet roclet to roxygen:

Roxygen: list(roclets = c("collate", "rd", "namespace", 
              "doctest::dt_roclet")) 

Then use roxygen2::roxygenize() or devtools::document() to build your package documentation.

For more information, see the package vignette.

  1. https://docs.python.org/3/library/doctest.html, https://doc.rust-lang.org/rustdoc/write-documentation/documentation-tests.html