Writing Unit Tests
Unit tests are written in C++ with the aid of macros from
Catch2 2.x. These tests are suited for larger scale
testing than sktest, as a large number of tests can be quickly run and the output easily checked.
This makes them suited for automation, because any failing test will be flagged so that any issues
can be resolved before merging the changes into the main repository of SplashKit.
When writing unit tests, you should aim to test the expected behaviour of a specific function or procedure. In addition to positive test cases (where the function or procedure takes valid input and should produce the expected output), consider negative cases (cases where the function or procedure has invalid input), as well as edge cases.
File structure
Section titled “File structure”Test files are located at:
Directorycoresdk
Directorysrc
Directorytest
- unit_test_main.cpp
unit_test_<name>.cpp
unit_test_main.cpp is the entry point for all unit tests. You do not need to modify this to write
your own tests or update existing ones.
The unit_test_<name>.cpp files contain tests for related parts of SplashKit. For example,
unit_test_utilities.cpp has tests for SplashKit’s utility functions. A test file must include the
Catch2 header file along with any other includes required:
#include "catch.hpp"Test syntax
Section titled “Test syntax”At a minimum, a unit test consists of a TEST_CASE and an assertion (usually REQUIRE):
TEST_CASE("gets the number of milliseconds that have passed since the program was started", "[current_ticks]"){ unsigned int result = current_ticks(); REQUIRE(result >= 0);}TEST_CASE(name, [,tags]) defines a test case with the given name and, optionally, one or more
tags.
REQUIRE evaluates an expression and aborts the test as a failure if the result is false.
REQUIRE_FALSE is similar but fails if the expression evaluates true. There are
other assertion macros but
these are the most common.
A test may contain multiple assertions:
TEST_CASE("random number float between 0 and 1 is generated", "[rnd]"){ float result = rnd(); REQUIRE(result >= 0); REQUIRE(result <= 1);}You may write tests that have some common steps, such as defining a variable. You can define one or
more SECTION(name) inside a TEST_CASE. The TEST_CASE is run from the start for each SECTION.
TEST_CASE("return a SplashKit resource of resource_kind with name filename as a string", "[file_as_string]"){ const resource_kind RESOURCE = resource_kind::BUNDLE_RESOURCE; const string RESOURCE_PATH = "blah.txt";
SECTION("filename is a valid file") { string result = file_as_string(RESOURCE_PATH, RESOURCE); string expected = "BITMAP,ufo,ufo.png\n"; REQUIRE(result == expected); } SECTION("filename is an empty string") { string result = file_as_string("", RESOURCE); string expected = ""; REQUIRE(result == expected); } SECTION("filename is an invalid file") { string result = file_as_string("invalid.txt", RESOURCE); string expected = ""; REQUIRE(result == expected); }}This test has three SECTIONs, so the TEST_CASE will run three times. Each time, the RESOURCE
and RESOURCE_PATH variables will be defined.