Cheer ships an in-process test runner that captures output and returns the handler's return value. No subprocess, no argv escaping, no port juggling.
Basic
test "greet prints a greeting" do
result = Cheer.Test.run(MyApp.CLI.Greet, ["world"])
assert result.return == :ok
assert result.output =~ "Hello, world!"
endCheer.Test.run/3 takes the same arguments as Cheer.run/3: a command
module, argv, and an optional prog.
Return shape
%Cheer.Test{
return: term(), # what run/2 returned, or {:error, :usage} on a usage error
output: String.t(), # everything written to stdout during the invocation
error_output: String.t() # cheer's diagnostics for this call
}error_output holds what cheer wrote as diagnostics during the call: usage
errors, suggestions, the help printed after an error, and deprecation warnings.
They go to a device private to the call, so error_output contains nothing
from other processes and exact or empty assertions on it are safe in
async: true tests. Text a command's own run/2 writes to :stderr is not
included; capture that with ExUnit.CaptureIO.capture_io(:stderr, ...), which
sees every process's stderr and so belongs in async: false tests when you
assert on it exactly.
Testing validation failures
When validation fails, cheer prints an error to stderr and does not invoke
run/2. Assert on the return value and error_output:
test "rejects out-of-range times" do
result = Cheer.Test.run(MyApp.CLI.Greet, ["world", "--times", "100"])
assert result.return == {:error, :usage}
assert result.error_output =~ "must be 1-10"
refute result.output =~ "Hello"
endTesting subcommand routing
test "db migrate with a target" do
result = Cheer.Test.run(Devtool.CLI, ["db", "migrate", "--target", "20240101"])
assert result.output =~ "Migrating to version 20240101"
endSame as production: the router walks the tree, parses each level's options,
and dispatches to the leaf's run/2.
Testing help output
test "help includes all subcommands" do
result = Cheer.Test.run(Devtool.CLI, ["--help"])
assert result.output =~ "server"
assert result.output =~ "db"
endIntegration tests
For end-to-end tests that exercise the real escript binary, use the
usual System.cmd/2 against your built artifact. Cheer's test runner
is for fast, in-process unit tests of parsing and handler logic, not
for testing the escript launcher itself.
See also
- REPL mode -- interactive equivalent of the in-process runner.