| Title | A Simple Package for Testing R Packages |
| Version | 1.1.1 |
| Description | A minimal, dependency-free testing framework for R packages. Write tests as simple R expressions that return TRUE, using assert() for assertions (with informative error messages on failure), has_error() / has_warning() / has_message() for testing conditions, and test_pkg() to run all tests with full access to internal (non-exported) package functions. Snapshot testing via Markdown files is also supported. |
| License | MIT + file LICENSE |
| URL | https://github.com/yihui/testit |
| BugReports | https://github.com/yihui/testit/issues |
| Author | Yihui Xie |
testit is a minimal testing package for R with zero dependencies. If you can
write an R expression that returns TRUE, you can write a test with testit.
From CRAN:
install.packages('testit')
Development version:
install.packages('testit', repos = 'https://yihui.r-universe.dev')
The core idea: wrap conditions in parentheses () inside assert(). If the
condition is TRUE, the test passes silently. If it is FALSE, you get an
error with the message you provided.
library(testit)
assert('one plus one is two', {
(1 + 1 == 2)
})
You can put multiple conditions in one assert() call, and mix in setup code
(lines without parentheses are just evaluated normally):
assert('basic arithmetic works', {
x = 1 + 1
(x == 2)
(x > 0)
})
To test if two objects are identical, use %==% (a shortcut for identical()).
When a %==% comparison fails inside assert(), you get a helpful diff showing
what was different:
assert('identical comparison', {
(c(1, 2, 3) %==% 1:3)
})
testit has one rule: an expression in parentheses () is a test condition
that must evaluate to TRUE. Everything else is ordinary R code.
assert('a descriptive message about what you are testing', {
# setup code (no parentheses = not checked)
x = sqrt(4)
# test conditions (parentheses = must be TRUE)
(x == 2)
(x > 0)
(is.numeric(x))
})
That’s it. No special matchers to memorize, no DSL to learn.
Use has_error(), has_warning(), and has_message() to verify that code
signals the expected condition:
assert('errors are caught correctly', {
(has_error(log('a')))
(has_error(stop('oops'), 'oops')) # also match the error message
(!has_error(log(1))) # no error here
})
assert('warnings are caught correctly', {
(has_warning(warning('watch out')))
(has_warning(1:2 + 1:3, 'longer object'))
})
Snapshot tests let you verify printed output by recording it in a Markdown file.
Place files named test-*.md in your tests/testit/ directory:
# Printing a sequence
```r
1:5
```
```
[1] 1 2 3 4 5
```
The R code block (```r) is executed and its output is compared to the
following plain code block (```). If the output changes, the test
fails with a diff. To accept the new output, run:
test_pkg(update = TRUE)
You can write explanatory text anywhere in the file – only code blocks are evaluated.
Create the directory tests/testit/ in your package.
Write test files named test-*.R (and optionally test-*.md for
snapshots).
Create tests/test-all.R with:
library(testit)
test_pkg('yourpkg')
library(testit) is required because test scripts call assert() and other
testit functions directly. Without it, you will get errors like “could not
find function assert”.
That’s all. R CMD check will run your tests automatically. In RStudio, you can
also press Ctrl/Cmd + Shift + T to run tests during development. For this to
work, go to the menu Build > Configure Build Tools... and make sure “Use
devtools package functions if available” is unchecked (otherwise RStudio
will try to use testthat conventions instead).
If you have shared setup code, put it in files named helper*.R (e.g.,
helper.R, helper-utils.R) in the same test directory. They are sourced
before any test file runs.
Global helpers in the parent directory (e.g., tests/helper.R) are also
sourced – before the subdirectory-level helpers. This is useful when you have
multiple test subdirectories (e.g., tests/testit/, tests/test-cran/) and
want to share common utilities across all of them.
test_pkg() runs your tests inside the package namespace, so you can call
non-exported (internal) functions directly – no need for the ::: operator.
testit is intentionally minimal. There is one rule to remember: parentheses
around an expression means “this must be TRUE.” There are no matchers like
expect_equal vs. expect_identical vs. expect_equivalent to choose between.
The tradeoff is that you get fewer bells and whistles (no mocking, no parallel execution). If you want a simple, dependency-free testing tool that stays out of your way, testit is a good fit.
If you want to convert your existing testthat tests to testit, you may take a look at this post https://yihui.org/en/2026/05/testthat-to-testit/. If you use AI assistance, this should be a straightforward task.
Although he did not really mean it, Xunzi said something that happens to apply well to unit testing:
不积跬步,无以至千里;不积小流,无以成江海。
(A journey of a thousand miles begins with a single step; a great river is formed from many small streams.)
This package is free and open source software, licensed under MIT.
To cite the package testit in publications, please use:
Xie Y (2026). testit: A Simple Package for Testing R Packages. R package version 1.1.1, https://github.com/yihui/testit.
@Manual{,
title = {testit: A Simple Package for Testing R Packages},
author = {Yihui Xie},
year = {2026},
note = {R package version 1.1.1},
url = {https://github.com/yihui/testit},
}