#include <testsoon.hpp> #include <iostream> TEST(compiler_check) { Equals(1, 1); // let's hope it works!! } TEST_REGISTRY; int main() { testsoon::default_reporter rep(std::cout); testsoon::tests().run(rep); }
In order to compile this ... important test, you first need to make sure that a recent testsoon.hpp is in your include path. It can be found in the include/ directory of the distribution. You may just copy it into your project folder. No other installation is required.
If you compile and run this program, you should see something like this on your console:
"simple.cpp" : . 1 tests, 1 succeeded, 0 failed.
I guess this means that we can trust our compiler a little bit. Or so it seems. Seriously, this is our first successful test. Let me explain what the code above actually means. I shall do this by thoroughly commenting the code.
// You really can guess why we do this. #include <testsoon.hpp> #include <iostream> // Declare a simple test with name "compiler_check". Note that no quotes are // required here. TEST(compiler_check) { // Check whether the two numbers are equal. Equals(1, 1); } // This line is required _once_ per executable. It ensures that if the code // compiles, everything works smoothly. The principle here: no surprises. TEST_REGISTRY; int main() { // Declare a reporter. The default_reporter should be a sensible setting. // That's why it's the default. // We need to pass it a reference to a std::ostream object to print to, // usually just std::cout. testsoon::default_reporter rep(std::cout); // Run all tests. testsoon::tests().run(rep); }
So now let's play around and test something different: are 1 and 2 equal? Change the check as follows:
Equals(1, 2);
Now, the output should look like something like this:
"simple.cpp" : [F=3.4] Error occured in test "compiler_check" in "simple.cpp" on line 3 in check on line 4. Problem: not equal: 1 and 2 Data: 1 2 1 tests, 0 succeeded, 1 failed.
Obviously, both numbers differ. Lets look at the first strange thing: "[F=3.4]". This little thing means that there was a failure in the test on line 3 (simple.cpp), to be exact the check on line 4 failed. (I used the version without comments.)
The same information is represented below and with additional information. "Data" are the two parameter values to Equals. This is necessary because in other situations the "problem" might not be "not equal: 1 and 2" but "not equal: a and b" where a and b are variables. In this case, "data" would contain the values of both variables in (readable) string representation.
In most circumstances you will structure a test executable like this:
TEST_REGISTRY
; and main()
.
TEST_GROUP(group_one) { TEST() { Check(!"unnamed test in group_one"); } TEST(named) { Check(!"named test in group_one"); } } TEST_GROUP(group_two) { TEST() { Check(!"only test in group_two"); } TEST_GROUP(nested) { TEST() { Check(!"except if you count this test in a nested group"); } } }
The Checks will all fail because they are passed a false value. !
applied to a non-null pointer value is always false
.
XTEST() {} // unnamed test XTEST((name, "my test")) {} // named test XTEST((n, "my other test")) {} // a named test, too XTEST((parameter1_name, parameter1_value) (parameter2_name, parameter2_value)) // illegal but demonstrates how to use multiple parameters
XTEST enables you to use named parameters. Some parameters have short and long names, like name, alias n. This syntax does not make much sense so far, but you will see how it is useful later.
XTEST((name, "my test") (fixture, my_fixture_class)) { fixture.do_something(); // the fixture is passed through the variable with the same name } XTEST((n, "my test") (f, my_fixture_class)) { fixture.do_something(); } FTEST(my test, my_fixture_class) { fixture.do_something(); }
We recommend you to choose a style and stick to it (mostly). But keep in mind that XTEST is the most powerful.
group_fixture_t
. Here come the examples:
TEST_GROUP(group1) { typedef fixture_for_group1 group_fixture_t; XTEST((group_fixture, 1)) { group_fixture.do_something_better_than_i_can_imagine(); } XTEST((n, "differently named") (gf, 1)) { group_fixture.hey_hey_hey(); } GFTEST(and yet another name) { group_fixture.call_this_method(); } }
(generator, (class)(p1)(p2)...(pN))where
class
is the name of the generator class and p1
to pN
are the parameters to be passed to the constructor.
The generated value is passed through the value
variable (const
).
Example:
XTEST((generator, (testsoon::range_generator)(0)(9))) { Check(0 <= value); Check(value < 9); }
value
variable.range:
(range, (type, begin, end))
Example:
array
or testsoon::array_generator but is way more convenient. It currently depends on Boost.Assign though.Parameter syntax:
(values, (type)(value1)(value2)...(valueN))
Example:
XTEST((values, (std::string)("x")("y")("z"))) { Check(value == "x" || value == "y" || value == "z"); }
Parameter syntax:
(array, (element_type, array_name))
Example:
char const * const array[] = { // not problematic to name the array like this! "abc", "xyz", "ghlxyfxt" }; XTEST((array, (char const *, array))) { Not_equals(value[0], '?'); }
Parameter syntax:
(2tuples, (element0_type, element1_type)(element0_1, element1_1)(element0_2, element1_2)...(element0_N, element1_N))
The type of value will be boost::tuple<element0_type, element1_type>. You should also include <boost/tuple/tuple_io.hpp>
Example:
#include <boost/tuple/tuple_io.hpp> // Check if strlen works properly ;-) XTEST((2tuples, (char const *, std::size_t)("hey", 3)("hallo", 5))) { Equals(std::strlen(value.get<0>()), value.get<1>()); }