Package {testit}


Type: Package
Title: A Simple Package for Testing R Packages
Version: 1.0
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
Encoding: UTF-8
Config/roxygen2/version: 8.0.0
NeedsCompilation: no
Packaged: 2026-05-13 03:30:46 UTC; yihui
Author: Yihui Xie ORCID iD [aut, cre] (URL: https://yihui.org), Tomas Kalibera [ctb], Steven Mortimer [ctb]
Maintainer: Yihui Xie <xie@yihui.name>
Repository: CRAN
Date/Publication: 2026-05-13 05:10:15 UTC

Assert that conditions are true, with an informative failure message

Description

Test that one or more conditions are TRUE. If any condition fails, an error is raised with the fact message, making it easy to identify which test failed and why. This is the primary function for writing tests with testit.

The infix operator ⁠%==%⁠ is a shortcut for identical() that provides helpful diagnostics on failure. x %==% y returns TRUE if x and y are identical, and FALSE otherwise. When used inside assert(), a failing ⁠%==%⁠ comparison will display both values via str() so you can see exactly what differed.

Usage

assert(fact, ...)

x %==% y

Arguments

fact

A character string describing what is being tested. This message is shown when an assertion fails, so make it descriptive (e.g., 'log() returns correct values'). If fact is not a character string, it is treated as a test expression (i.e., the message is optional).

...

An R expression wrapped in {}; see Details.

x, y

Two R objects to be compared for identity.

Details

The recommended usage is to pass a single expression wrapped in {} as the second argument. Inside {}, any statement-level sub-expression wrapped in parentheses ⁠()⁠ is treated as a test condition – its value is checked and must be TRUE. Parentheses used for grouping within a larger expression (e.g., (a + b) * c) are not checked. Sub-expressions without parentheses are ordinary R code (e.g., variable assignments or setup steps) and are never checked.

⁠()⁠ tests work inside if, for, while, and repeat bodies. Internally, assert() walks the expression tree and transforms statement-level ⁠()⁠ into checks before evaluating the entire block in one frame (so on.exit() works as expected).

Value

Invisible NULL if all conditions pass. If any condition fails, an error is signaled that includes the fact message and the expression that failed. For ⁠%==%⁠, TRUE or FALSE.

Note

Key differences from stopifnot():

Examples

library(testit)
assert('T is bad for TRUE, and so is F for FALSE', {
  T = FALSE; F = TRUE
  (T != TRUE)  # note the parentheses
  (F != FALSE)
})

assert('A Poisson random number is non-negative', {
  x = rpois(1, 10)
  (x >= 0)
  (x > -1)
})

# () works inside control structures too
assert('conditional test', {
  if (requireNamespace('base', quietly = TRUE)) (1 + 1 == 2)
})

Test whether an expression signals a condition

Description

Check if evaluating an expression produces a message, warning, or error. These functions are designed to be used inside assert() to verify that code signals the expected conditions. Optionally, you can match against the condition's text to ensure the right message/warning/error was signaled.

Usage

has_message(expr, message = NULL, ...)

has_warning(expr, message = NULL, ...)

has_error(expr, message = NULL, ...)

Arguments

expr

An R expression to evaluate.

message

An optional string to match against the condition text. Uses fixed (literal) matching by default. If provided, the function returns TRUE only when the condition is signaled and the message matches.

...

Additional arguments passed to grepl() for matching (e.g., fixed = FALSE to use regex, or ignore.case = TRUE). Note that fixed = TRUE is the default.

Value

TRUE if the condition was signaled (and the message matched, if provided), FALSE otherwise.

Examples

has_message(message('hello'))
has_message(1 + 1)
has_message(message('hello world'), 'hello')

has_warning(1 + 1)
has_warning(1:2 + 1:3)
has_warning(1:2 + 1:3, 'longer object length')

has_error(2 - 3)
has_error(1 + 'a')
has_error(stop('err'), 'err')
has_error(stop('error occurred'), 'error')

Run all tests for a package

Description

Discover and execute test files (⁠test-*.R⁠ and ⁠test-*.md⁠) for a package. Tests are run inside the package namespace, so you can call internal (non-exported) functions directly without the ::: operator.

Usage

test_pkg(package = pkg_name(), dir = NULL, filter = NULL, update = NA)

Arguments

package

The package name. By default, it is detected from the DESCRIPTION file.

dir

The directory containing test files. If NULL (the default), ⁠testit/⁠ or ⁠tests/testit/⁠ under the current working directory is used (whichever exists). You can also pass a custom path.

filter

An optional regular expression to select a subset of test files. Only files whose names match the pattern will be run. For example, filter = "plot" runs only test files with "plot" in their names.

update

Controls snapshot file behavior:

  • TRUE: always update snapshot files with actual output (never errors).

  • NA (default): update only if the file is tracked by Git (so you can review diffs before accepting).

  • FALSE: never update; always compare and error on mismatch.

Details

Test files are looked up in the ⁠testit/⁠ or ⁠tests/testit/⁠ directory by default. Files must be named ⁠test-*.R⁠ for regular tests or ⁠test-*.md⁠ for snapshot tests. Other files in the directory are ignored (but you can source() them from your tests if needed).

Helper files named helper*.R (e.g., helper.R, helper-utils.R) are sourced before any test file runs. Objects defined in helpers are available to all tests.

Each test file runs in a clean environment (previous test objects are removed), and the working directory is set to the directory containing the test file.

See https://pkg.yihui.org/testit/#snapshot-testing for more details about snapshot testing.

Value

Invisible NULL. If any tests fail, a single error is thrown at the end with all failure messages combined.

Note

You must call library(testit) before test_pkg(). Test scripts use assert() and other testit functions without the ⁠testit::⁠ prefix, so the package needs to be on the search path. Without library(testit), you will get "could not find function" errors.

All test scripts must be encoded in UTF-8 if they contain multibyte characters.

When filter or update are not explicitly provided, test_pkg() checks commandArgs(TRUE) for command-line arguments: --filter=PATTERN sets the filter, and --update sets update = TRUE. This allows you to pass these options via ⁠Rscript tests/*.R --filter=PATTERN --update⁠ without modifying individual test_pkg() calls.

Examples

## Not run: 
library(testit)
test_pkg('testit')

## End(Not run)