|
NAMEunittest —
Utilities to implement test programs
LIBRARYshtk_importunittest
DESCRIPTIONTheunittest module provides a framework with which to
implement test programs.
A test program implemented with the
Program entry pointTest programs implemented usingunittest must use the
shtk_unittest_main(3)
function as their entry point. There are two mechanisms to achieve this.
The first is to end the test program with the following definition
of main() { shtk_unittest_main "${@}"; } The second is to tell shtk(1) at build time to use shtk_unittest_main(3) as the program's entry point: $ shtk build -m shtk_unittest_main module_test.sh In general, prefer the latter mechanism. Asserts vs. expectsTheunittest library provides a variety of helper check
functions. One such example is the ‘equal’ check, which allows
the caller to compare two values for equality and fail the test case with the
appropriate error message if the values differ.
Each check is offered in two flavors: an assert
and an expect, which in the previous example means we have
access to the two corresponding functions
ScopingAll functions provided by theunittest library are
prefixed by ‘shtk_unittest_’ as you would expect from the coding
practices of shtk . However, such long prefix is
inconvenient when writing test programs, as test programs are a very special
case of scripts in which a domain-specific language makes sense.
Therefore, for simplicity reasons, test cases have access to
shortened names of the Standalone test casesStandalone test cases are defined by top-level functions whose name ends with the ‘_test’ suffix and are registered as test cases with the shtk_unittest_add_test(3) function. Such test cases are run independently of each other, with no common setup nor teardown code among them.Test fixturesTest fixtures are collections of related test cases that may share optional setup and teardown methods. Test fixtures are defined by top-level functions whose name ends with the ‘_fixture’ suffix and are registered as fixtures with the shtk_unittest_add_fixture(3) function.Within fixture fuctions, there may be a
Test environmentThe runtime engine (usually kyua(1)) is responsible for executing the test program under a controlled directory and with a sanitized environment.However, due to the nature of shell-based test programs,
One time setup and teardownTest programs may optionally define top-levelone_time_setup and
one_time_teardown .
The code supplied in the The code supplied in the It is important to mention that these one-time setup and teardown routines run in the parent directory of the executed test cases. In other words: if the setup routine creates any file to be shared across all tests, the tests will have access to such files by looking them up in their parent directory. Test resultsAny test case can complete with one of the following results:
EXAMPLESThe most basic test program that can be written is the following, which provides a simple test case for cp(1)'s-f flag:
shtk_import unittest shtk_unittest_add_test cp_f_forces_override cp_f_forces_override_test() { echo "first" >first echo "second" >second chmod 555 second # First make sure that cp without -f fails. assert_command -s exit:1 -e ignore cp first second # Now run a second attempt with -f and verify that the command # exits successfully and it is silent. assert_command cp -f first second cmp -s first second || fail "source and destination do not match" } main() { shtk_unittest_main "${@}"; } A more complex test program can use fixtures to group related test cases and to provide common setup and teardown code for each of them: shtk_import unittest shtk_unittest_add_fixture cp setup() { # Create common files used by all test cases. Note that this runs # once per test case, so state is not shared among them. echo "first" >first echo "second" >second } teardown() { # Common cleanup to be executed at the end of the test case, no # matter if it passes or fails. rm -f first second } shtk_unittest_add_test override_existing_file override_existing_file_test() { assert_command cp first second cmp -s first second || fail "source and destination do not match" } shtk_unittest_add_test f_forces_override f_forces_override_test() { chmod 555 second assert_command -s exit:1 -e ignore cp first second assert_command cp -f first second cmp -s first second || fail "source and destination do not match" } } main() { shtk_unittest_main "${@}"; } Lastly, the most complex test program is depicted here, which includes a combination of fixtures and test cases with one-time setup and teardown routines: shtk_import unittest one_time_setup() { ... initialization code shared by all tests in the program ... } one_time_teardown() { ... clean up code shared by all tests in the program ... } shtk_unittest_add_fixture clients clients_fixture() { setup() { ... initialization code shared by all tests in the fixture ... } teardown() { ... cleanup code shared by all tests in the fixture ... } shtk_unittest_add_test add add_test() { ... first test in the fixture ... } shtk_unittest_add_test modify modify_test() { ... second test in the fixture ... fail "And it fails" } } shtk_unittest_add_test initialization initialization_test() { ... standalone test not part of any fixture ... skip "But cannot run due to some unsatisfied condition" } # Either do this or, preferably, pass -mshtk_unittest_main to # "shtk build" when compiling the test program and don't define main. main() { shtk_unittest_main "${@}"; } SEE ALSOshtk(3), shtk_unittest_add_fixture(3), shtk_unittest_add_test(3), shtk_unittest_delayed_fail(3), shtk_unittest_fail(3), shtk_unittest_main(3), shtk_unittest_set_expected_failure(3), shtk_unittest_skip(3)Checksshtk_unittest_assert_command(3), shtk_unittest_assert_equal(3), shtk_unittest_assert_file(3), shtk_unittest_assert_not_equal(3), shtk_unittest_expect_command(3), shtk_unittest_expect_equal(3), shtk_unittest_expect_file(3), shtk_unittest_expect_not_equal(3)HISTORYunittest first appeared in shtk
1.6.
Visit the GSP FreeBSD Man Page Interface. |