Testing command line apps with App::Cmd
Ricardo Signes' App::Cmd has been praised a lot so I gave it a try for my recent command line app. In summary, the module is great although I missed some minor features and documentation (reminder to all: if you miss some feature in a CPAN module, don't create yet another module but try to improve the existing one!). One feature I like a lot is how App::Cmd facilitates writing tests for command line apps. After having written a short wrapper around App::Cmd::Tester my formerly ugly unit tests look very simple and clean. Have a look at this example:
use Test::More;
use App::PAIA::Tester;
new_paia_test;
paia qw(config);
is stdout, "{}\n";
is error, undef;
paia qw(config -c x.json --verbose);
is error, "failed to open config file x.json\n";
ok exit_code;
paia qw(config --config x.json --verbose foo bar);
is output, "# saved config file x.json\n";
paia qw(config foo bar);
paia qw(config base http://example.org/);
is exit_code, 0;
is output, '';
paia qw(config);
is_deeply stdout_json, {
base => 'http://example.org/',
foo => 'bar',
}, "get full config"
done_paia_test;
The application is called paia
- that's how it called at command line and that's how it is simply called as function in the tests. The wrapper class (here: App::PAIA::Tester) creates a singleton App::Cmd::Tester::Result object and exports its methods (stdout
, stderr
, exit_code
...). This alone makes the test much more readable. The wrapper further exports two methods to set up a testing environment (new_paia_test
) and to finish testing (done_paia_test
). In my case the setup creates an empty temporary directory, other applications might clean up environment variables etc. Depending on your application you might also add some handy functions like stdout_json
to parse the app's output in a form that can better be tested.
Leave a comment