Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Automated testing of command line interfaces

Author: Roman Neuhauser
Copyright: This document is in the public domain.


rnt is a tool for automated testing of command line interfaces. It comprises two shell scripts portable enough to run at least on FreeBSD, GNU/Linux and MSYS (Windows).

rnt has notions of test suite and test case.

Test Suite

A test suite is a directory containing zero or more test cases. A test suite may contain other entries beside test cases, they will be ignored.

Test Case

A test case is an immediate test suite subdirectory with a name matching ^[0-9]{3,}(-[a-z0-9]+)+$. It should contain these files:

This file is output at the terminal if the test fails.
A script with the command(s) under test.
Expected exit code.
Expected contents of standard output.
Expected contents of standard output.

cmd is required, the remaining files are optional (with a caveat about exit.expected, see below). If any of the *.expected files is missing, it's treated as if it was present and empty. A test case may contain other files matching *.expected, these are treated the same as the usual *.expected files listed above (see below). Any number of other files and directories may be present in the test case directory.


rnt runs each test case in the given test suite, printing . (a dot) for a successful case, F for a failed one. After all test cases have been run, rnt prints details of failures if any: for each failed test case, its README file is output if it exists, followed by the diffs.

For each test case, rnt chdirs into the test case directory and runs cmd, storing stdout, stderr and the exit code in out.actual, err.actual and exit.actual, respectively.

Then, rnt gathers all *.actual and *.expected files in the test case directory. The list of files considered is not limited to the out.*, err.* and exit.* files listed above: all files with either of those two extensions are included. It's not necessary for both foo.expected and foo.actual to be present; if either side is missing, it's treated as present and empty.

Each pair of foo.expected, foo.actual gets diffed; if any pair has non-empty diff, the test is considered to have failed. Note that since the actual exit code is always a number (never the empty string), a test case without exit.expected will always fail.

*.actual and *.diff files of successful tests are removed, while failed test cases are left as-is for examination.


Git Subtree

Use git subtree in a project using Git:

git remote add rnt
git subtree add -P rnt --squash rnt master

Git Submodule

This method has several disadvantages: submodule trees do not show up in git-archive(1) output, and working copies of such a repository need to be created with git clone --recursive, otherwise git submodule update --init is necessary to clone and check out the submodule.

git submodule add rnt
git submodule update --init

Plain Old Copy

Using another versioning control system?

mkdir rnt
curl -s \
| tar -xzf - -C rnt --strip-components=1
svn add rnt
svn ci


Modify your Makefile to include a check target of the following structure:

check: all
  SHELL=$(SHELL) $(SHELL) <rnt>/ <suite> [args...]
  • <rnt> is the path to rnt.
  • <suite> is the path to your tests.
  • [args...] is any number of arguments (possibly none), these are passed to each test.


rnt is quite different from a number of other shell-oriented testing tools like


Automated testing of commandline interfaces




No releases published


No packages published