Write Test Fixtures Using Polyspace Test C++ API
You can group multiple tests written with the Polyspace® Test™ xUnit API in test suites. See Group C/C++ Tests into Suites with Common Setup and Teardown Code. If your tests use the same setup and cleanup code, you can use the Polyspace Test C++ API to create a test fixture to share the setup and cleanup code between the tests. You can also create a suite fixture to reuse the setup and cleanup code between tests across different test suites.
For example, if you run tests on an object that is costly to instantiate, such as a large database, you can create the object once during the fixture setup, and then share the object between the different tests.
This example shows how to write a C++ test fixture class with setup and teardown methods.
Prerequisites
This topic describes test authoring using the Polyspace Test xUnit API. To compile these tests, you are required to know some file paths in advance. For your convenience, you can define environment variables to stand for the file paths, or otherwise include the file paths in your build. For more information, see Set Up C/C++ Testing and Code Profiling Using Self-Managed Builds.
Workflow
To reuse setup and cleanup code between tests across different test suites:
Declare a class derived from
pst_suite_fixture, for example,class.suiteWithFixture: public pst_suite_fixture{}The inheritance is optional. If you do not derive your class from
pst_suite_fixture, you must at least provide default methods for all the methods described in the next step.Inside the class, declare objects to use in your tests and define these methods as needed. Use only these names for each method:
static void suite_setup(){// function body}— This method is called once before any test in the suite starts.static void suite_teardown(){// function body}— This method is called once after all the tests in the suite complete.void test_setup() {// function body}— This method is called before each test runs.void test_teardown() {// function body}— This method is called after each test runs.
Use macro
PST_SUITE_WITH_FIXTUREto declare a test suite that uses the suite fixture, for examplePST_SUITE_WITH_FIXTURE(.testSuiteName,suiteWithFixture);Add tests to the test suite. To access objects that you declared in the class from step 2, use a fixture access macro. For example, in this code snippet, the test
accesses the objecttestNamethat was declared in classaContainer:suiteWithFixturePST_TEST(testSuiteName, testName){ T myContainer = PST_SUITE_TEST_FIXTURE_PTR() -> aContainer; //rest of test body }
When you define tests with the Polyspace
Test C++ API, you do not need to explicitly register the tests. Only if you compile your tests into a static library that you later link with the file containing the main function, register your tests manually in the main function.
Example
Example Files
Find the files for this tutorial in the folder . Copy these files to a writable location and continue the tutorial. Here, polyspaceroot\polyspace\examples\doc_pstest\cpp_example is the Polyspace installation folder, for example, polyspacerootC:\Program Files\Polyspace\R2026a.
Inspect Function Under Test and Requirements
The example file Ranks.cpp defines three methods of class Ranks:
Ranks::addToList(const std::string& name, const size_t& score), which takes a name and score as an input and adds them as a pair to a players list that is sorted by scores.Ranks::removeFromList(const std::string& name), which takes a name as an input and removes the corresponding pair from the players list if the name exists.void Ranks::resetList(), which removes all entries from the players list.
#include "ranks.hpp"
void Ranks::addToList(const std::string& name, const size_t& score) {
if (playersList.size()) {
// Find first instance of smaller score and insert
// before that instance
auto insertPosition = std::find_if(playersList.begin(),
playersList.end(),
[score](str_uint_pair i) {
return i.second < score; });
playersList.insert(insertPosition, std::make_pair(name, score));
} else {
playersList.push_back(std::make_pair(name, score));
}
}
void Ranks::removeFromList(const std::string& name) {
auto erasePosition = std::remove_if(playersList.begin(),
playersList.end(),
[name](str_uint_pair i) {
return i.first == name; });
if (erasePosition != playersList.end()) {
playersList.erase(erasePosition, playersList.end());
}
}
void Ranks::resetList() {
playersList.clear();
}Suppose that you want to create separate test suites to test adding and removing pairs from the list. You might want to create a Ranks object with a prepopulated list that you can then reuse between the different suites.
In this case, create a class where you define test setup and teardown methods for a Ranks object.
Write Test
The following class in the file suite_test.cpp defines a suite fixture with these methods and members:
test_setup()— This method is called before each test runs and populates the list with 3 entries.test_teardown()— This method is called after each test and removes all the entries in the list.Ranks aRanks— This object instantiates the list during test setup.
To define a test suite that uses the suite fixture, use the PST_SUITE_WITH_FIXTURE macro. You can then use the PST_TEST macro to add tests to the suite, for example:
#include <pstunit.h>
#include <pstunit_main.h>
#include "ranks.hpp"
// Test using fixtures
class my_suite_with_fixture : public pst_suite_fixture {
public:
void test_setup() {
aRanks.addToList("Jane Doe", 50);
aRanks.addToList("John Smith", 60);
aRanks.addToList("Ada Lovelace", 55);
}
void test_teardown() {
aRanks.resetList();
}
Ranks aRanks;
};
//Test adding player
PST_SUITE_WITH_FIXTURE(suite_add_player, my_suite_with_fixture);
PST_TEST(suite_add_player, test_size_one_addition) {
Ranks myRanks = PST_SUITE_TEST_FIXTURE_PTR()->aRanks;
// Add new player
auto expected_numPlayers = myRanks.getNumPlayers() + 1;
std::string name = "Richard Roll";
size_t score = 65;
myRanks.addToList(name, score);
PST_VERIFY_EQ_UINT(expected_numPlayers, myRanks.getNumPlayers());
}
PST_TEST(suite_add_player, test_rank_one_addition) {
Ranks myRanks = PST_SUITE_TEST_FIXTURE_PTR()->aRanks;
// Add new player with 2nd highest score
auto expected_numPlayers = myRanks.getNumPlayers() + 1;
std::string name = "John Doe";
size_t score = 57;
myRanks.addToList(name, score);
size_t expected_rank = 2;
PST_VERIFY_EQ_UINT(expected_rank, myRanks.getPlayerRank(name));
}suite_test.cpp also contains a test suite suite_remove_player (not shown here) to test the removal of entries from the list.For each test, you access the Ranks object from the class my_suite_with_fixture by using the PST_SUITE_TEST_FIXTURE_PTR fixture access macro.
You do not need additional setup to use the prepopulated list in the test. For example:
The Polyspace Test C++ API automatically registers the tests. You do not need to explicitly invoke test registration macros.
You do not need to provide a
mainfunction.
Simply include the header file pstunit_main.h in your code. The header file is available in the include folder of your Polyspace
Test installation, for example . Here, polyspaceroot/polyspace/pstest/pstunit/include is the Polyspace installation folder, for example, polyspaceroot/usr/local/Polyspace/R2026a.
Execute Test and Inspect Results
To run the tests, compile the files Ranks.cpp, suite_test.cpp, and the files shipped with Polyspace
Test:
g++ -std=c++11 ranks.cpp suite_test.cpp <PSTUNIT_SOURCE> -I <PSTUNIT_INCLUDE> -o testrunner
<PSTUNIT_SOURCE> and <PSTUNIT_INCLUDE>, see Set Up C/C++ Testing and Code Profiling Using Self-Managed Builds.Run the test executable:
testrunner.exe
./testrunner in Linux®).You see that all tests in both suites pass.
| Running tests | | |-----------------|------------| | Running | suite | suite_add_player | suite_test.cpp |-----------------|------------| | Running | s.setup | suite_add_player | PASS | s.setup | suite_add_player | Running | test | suite_add_player/test_size_one_addition | PASS | test | suite_add_player/test_size_one_addition | Running | test | suite_add_player/test_rank_one_addition | PASS | test | suite_add_player/test_rank_one_addition | Running | s.teardown | suite_add_player | PASS | s.teardown | suite_add_player |-----------------|------------| | PASS | suite | suite_add_player |-----------------|------------| | Running | suite | suite_remove_player | suite_test.cpp |-----------------|------------| | Running | s.setup | suite_remove_player | PASS | s.setup | suite_remove_player | Running | test | suite_remove_player/test_size_one_delete | PASS | test | suite_remove_player/test_size_one_delete | Running | test | suite_remove_player/test_size_fake_delete | PASS | test | suite_remove_player/test_size_fake_delete | Running | s.teardown | suite_remove_player | PASS | s.teardown | suite_remove_player |-----------------|------------| | PASS | suite | suite_remove_player | | Total | Passed | Failed | Incomplete |--------|--------|--------|--------|------------ | Suites | 2 | 2 | 0 | 0 | Tests | 4 | 4 | 0 | 0