Run Perl Tests Reliably with prove
You will finish with a repeatable way to run a Perl test file or test directory, read the TAP result, pass test arguments, and rerun only known failures. The examples use the locally installed prove from Perl 5.38.2, with TAP::Harness v3.44.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need a shell, Perl, and a project containing tests written in the TAP format, commonly files ending in .t under t/. Nothing in this guide needs elevated privileges. Run tests as the same user who normally edits and builds the project.
1. Check the installed command
Start by checking which executable will run and which version it reports:
$ command -v prove
/usr/bin/prove
$ prove --version
TAP::Harness v3.44 and Perl v5.38.2
The exact version can differ on another host. Keep this check in bug reports when a test behaves differently between machines. The command is part of the installed perl package here:
$ dpkg-query -W -f='${Package} ${Version}\n' perl
perl 5.38.2-3.2ubuntu0.6
Checkpoint: if command -v prove prints nothing, stop and repair the Perl installation or your PATH. Do not work around an unknown executable by running a similarly named script from the current directory.
2. Run one test file first
Change to the project directory and name one test explicitly. This avoids being distracted by an unrelated test while you establish that the harness works:
$ cd /path/to/project
$ prove --norc -v t/basic.t
t/basic.t ..
1..2
ok 1 - first
ok 2 - arithmetic
ok
All tests successful.
Files=1, Tests=2, 0 wallclock secs
Result: PASS
Use the real path to one of your test files in place of /path/to/project and t/basic.t. The -v option prints each test line. --norc is useful for a clean diagnostic run because it stops prove reading project or home configuration files. Without it, ~/.proverc and ./.proverc are read before command-line options.
A zero exit status means the harness and the selected test completed successfully. Check it directly when a script needs to make a decision:
$ prove --norc t/basic.t
$ printf 'prove exit status: %s\n' "$?"
prove exit status: 0
A failing test makes prove exit non-zero. Preserve that status in CI or a shell script rather than piping the command into another program and accidentally hiding the failure.
3. Run the project's normal test set
Once one file passes, run the directory. With no file or directory argument, prove looks for files matching t/*.t; naming t/ makes the scope clear:
$ prove --norc t/
t/basic.t .. ok
t/paths.t .. ok
All tests successful.
Files=2, Tests=7, 0 wallclock secs
Result: PASS
These file names and counts are examples. Your output depends on the project. If tests live below several directory levels, add -r or --recurse to descend recursively:
$ prove --norc -r t/
Do not add recursive discovery merely because a project has other scripts nearby. Confirm the paths first, since running an unintended test can create files, contact services, or consume test data.
4. Separate prove options from test arguments
Arguments intended for the test must follow the separator ::. Everything before it belongs to prove:
$ prove --norc -v t/api.t :: --url https://staging.example.invalid
t/api.t ..
ok 1 - endpoint is reachable
ok
Result: PASS
Every selected test receives the same arguments. Quote values containing spaces or shell metacharacters. Treat URLs, file names and credentials as data, not as shell syntax. Do not put a secret directly in a command if your shell history or CI logs can record it; use the project's supported environment or secret mechanism instead.
Checkpoint: if a test says it received an unknown option, inspect the position of ::. If :: is absent, prove may try to interpret the test's option as its own.
5. Use project libraries and build output
Tests often need modules from the project's source or build directories. Use -l to add lib to the Perl include path, or -b to add blib/lib and blib/arch:
$ prove --norc -l t/
$ prove --norc -b t/
These options affect how the Perl tests are loaded; they do not build the project. Run the project's build step first when blib does not exist. If the test still cannot locate a module, inspect the project's documented dependency and build process instead of adding random include paths.
6. Preview selection before running tests
Use dry-run mode when you are unsure which files a directory or recursive search will select:
$ prove --norc --dry t/
t/basic.t
t/paths.t
Dry-run prints the tests that would run and does not execute them. It is a useful checkpoint before a broad or expensive test command. It does not validate the tests themselves.
7. Rerun failures with saved state
For a larger suite, save the run state, then select only failures:
$ prove --norc -b --state=save t/
$ prove --norc -b --state=failed
t/paths.t .. Failed 1/3
Failed 1/2 test programs. 1/5 subtests failed.
$ prove --norc -b --state=failed,save
The saved state is stored in .prove in the current directory. The last command reruns failures and updates that state, so newly passing tests are excluded from the next failure-only run. This file is project state, not a test result to edit by hand. If you need a clean run, remove .prove only after confirming it is the state file created by prove, or run from a clean working copy. Removing it loses the remembered selection but does not alter source code.
State is easy to misunderstand: --state=failed needs a previous saved run, while --state=save saves the current run. For a complete rerun after fixing a failure, name t/ explicitly rather than relying on an old selection.
8. Diagnose output without changing the test
Use -f or --failures to show failed tests, -o to show comments, and -p to show the full list of TAP parse errors. Use --merge only when you need standard error interleaved with standard output in diagnostic order:
$ prove --norc -v -f -p t/paths.t
$ prove --norc --merge t/paths.t
The merge option is deliberately specialised. If diagnostics written to standard error resemble TAP test lines, the harness can misinterpret them. Start with ordinary verbose output and add --merge only when ordering between diagnostics and results is the problem.
Parallel execution is available with -j N, but it can expose tests that share files, ports, databases or environment state. Begin with one job. Add parallel jobs only after the tests are demonstrably independent, and use --rules for tests that must remain sequential. Parallel output and timing can make a failure harder to reproduce.
Done means
- You confirmed the installed
proveexecutable and Perl version. - You ran one test file and checked its exit status.
- You previewed or named the intended test set before a broad run.
- You know that
--norcbypasses.provercand that configuration can change defaults. - You used
::to separate test arguments from harness options. - You can save state and rerun failures without editing source or test results.
- You have left parallel execution disabled unless the suite is safe for it.