Clone wiki

xUnit++ / TestEvents

Assert and Check

xUnit++ has a robust suite of test assert methods. While most C++ testing frameworks use preprocessor macros to implement only a few checks, xUnit++ provides two class instances with many built-in methods. And since these tests are not implemented with macros, you get much nicer feedback while editing (assuming your editor can provide such detail) and compiling.

There are three ways to assert test events: Assert, Check, and Warn. With one exception, they offer the same check methods. Assert will halt the test immediately if any check fails, Check will log the failure but continue, and Warn will not cause the test to fail by itself, but the "error" will be logged.

Warn.Fail();    // warning message logged, test is not a failure (yet)
Check.Fail();   // failure is logged, test is marked as failing, test execution continues
Assert.Fail();  // stops the test here
Check.Fail();   // test never executes this line

The Methods

As stated before, the test objects share the same check methods, with one exception: Assert offers Throws while Check and Warn do not.

  • Contains asserts that a container contains some value. Overloads exist for raw strings and std::string.
  • ContainsPred is an alternative form of Contains which takes a predicate instead of a value.
  • DoesNotContain asserts that a container does not contain some value. Overloads exist for raw strings and std::string.
  • DoesNotContainPred is an alternative form of DoesNotContain which takes a predicate instead of a value.
  • DoesNotThrow asserts that the given code does not throw any exceptions. Anything that resolves to the equivalent of void (*)() will work.
  • Equal tests object values for equality. There are overloads for raw strings, std::string, floating point types (with precision, instead of tolerance), and iterator ranges.
  • Empty will assert that the container object is empty. TContainer::empty() will be used if it exists, otherwise the container will be converted to a range using std::begin and std::end.
  • Fail will automatically fail the test.
  • False will fail the test if the supplied parameter resolves to true.
  • InRange checks that the given value fits within the range [min, max).
  • NotEmpty is the opposite of Empty.
  • NotEqual is the opposite of Equal.
  • NotInRange checks that the given value does not fit within the range [min, max).
  • NotNull checks that the value is not equal to nullptr.
  • NotSame verifies that the supplied objects are not the same object instance.
  • Null checks that the value is equal to nullptr.
  • Same checks that the supplied objects are the same object instance.
  • Throws is an Assert-only member that checks that the supplied code throws a specific exception. If it succeeds, it will return the exception to your test.
auto ex = Assert.Throws<std::exception>([]() { throw std::runtime_error(""); });

Printing Values

Some methods may try to print the values of the objects using to_string with argument-dependent lookup (Koenig lookup). To take advantage of this, implement a to_string function within your object's namespace.

namespace NS
    class A {};
    std::string to_string(const A &a) { return "A"; }

If a corresponding to_string can't be found, xUnit++ falls back to printing the object's type with typeid(obj).name().

Custom Messages

If you want to add a custom message to failing tests, use the overloaded operator <<.

Assert.Fail() << "This is an example message " << some_value;

File and Line Info

Normally, when a test fails the test runner will report the file and line number for the test itself. This is typically sufficient for most tests, as tests should really only assert one thing at a time. However, if you want to be specific about which check failed, each check method accepts an optional xUnitpp::LineInfo object. The easiest way to do this is to pass the LI macro as the final parameter to the test.

Assert.Equal(0, 1, LI) << "0 is never equal to 1!";

Extra Logging

If you need more logging output within the tests, use the Log object. Three levels of logging are implemented: Debug, Information, and Warning:

Log.Debug << "This is a debug-level message: " << some_value;
Log.Info << "This is an info-level message: " << some_value;
Log.Warn << "This is a warning-level message, and will automatically mark the running test has having a warning status. " << some_value;

The log levels will normally print the file and line of the test (like the check methods), but they also accept the LI macro:

Log.Info(LI) << "This message will include the exact line number.";