Appearance
Test fixtures
Defining test fixtures
Although Catch allows you to group tests together as sections within a test case, it can still be convenient, sometimes, to group them using a more traditional test fixture. Catch fully supports this too. You define the test fixture as a simple structure:
class UniqueTestsFixture {
private:
static int uniqueID;
protected:
DBConnection conn;
public:
UniqueTestsFixture() : conn(DBConnection::createConnection("myDB")) {
}
protected:
int getID() {
return ++uniqueID;
}
};
int UniqueTestsFixture::uniqueID = 0;
TEST_CASE_METHOD(UniqueTestsFixture, "Create Employee/No Name", "[create]") {
REQUIRE_THROWS(conn.executeSQL("INSERT INTO employee (id, name) VALUES (?, ?)", getID(), ""));
}
TEST_CASE_METHOD(UniqueTestsFixture, "Create Employee/Normal", "[create]") {
REQUIRE(conn.executeSQL("INSERT INTO employee (id, name) VALUES (?, ?)", getID(), "Joe Bloggs"));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
The two test cases here will create uniquely-named derived classes of UniqueTestsFixture and thus can access the getID()
protected method and conn
member variables. This ensures that both the test cases are able to create a DBConnection using the same method (DRY principle) and that any ID's created are unique such that the order that tests are executed does not matter.
Catch2 also provides TEMPLATE_TEST_CASE_METHOD
and TEMPLATE_PRODUCT_TEST_CASE_METHOD
that can be used together with templated fixtures and templated template fixtures to perform tests for multiple different types. Unlike TEST_CASE_METHOD
, TEMPLATE_TEST_CASE_METHOD
and TEMPLATE_PRODUCT_TEST_CASE_METHOD
do require the tag specification to be non-empty, as it is followed by further macro arguments.
Also note that, because of limitations of the C++ preprocessor, if you want to specify a type with multiple template parameters, you need to enclose it in parentheses, e.g. std::map<int, std::string>
needs to be passed as (std::map<int, std::string>)
. In the case of TEMPLATE_PRODUCT_TEST_CASE_METHOD
, if a member of the type list should consist of more than single type, it needs to be enclosed in another pair of parentheses, e.g. (std::map, std::pair)
and ((int, float), (char, double))
.
Example:
template< typename T >
struct Template_Fixture {
Template_Fixture(): m_a(1) {}
T m_a;
};
TEMPLATE_TEST_CASE_METHOD(Template_Fixture,
"A TEMPLATE_TEST_CASE_METHOD based test run that succeeds",
"[class][template]",
int, float, double) {
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
}
template<typename T>
struct Template_Template_Fixture {
Template_Template_Fixture() {}
T m_a;
};
template<typename T>
struct Foo_class {
size_t size() {
return 0;
}
};
TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Template_Fixture,
"A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test succeeds",
"[class][template]",
(Foo_class, std::vector),
int) {
REQUIRE( Template_Template_Fixture<TestType>::m_a.size() == 0 );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
While there is an upper limit on the number of types you can specify in single TEMPLATE_TEST_CASE_METHOD
or TEMPLATE_PRODUCT_TEST_CASE_METHOD
, the limit is very high and should not be encountered in practice.
Signature-based parametrised test fixtures
Introduced in Catch2 2.8.0.
Catch2 also provides TEMPLATE_TEST_CASE_METHOD_SIG
and TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG
to support fixtures using non-type template parameters. These test cases work similar to TEMPLATE_TEST_CASE_METHOD
and TEMPLATE_PRODUCT_TEST_CASE_METHOD
, with additional positional argument for signature.
Example:
template <int V>
struct Nttp_Fixture{
int value = V;
};
TEMPLATE_TEST_CASE_METHOD_SIG(
Nttp_Fixture,
"A TEMPLATE_TEST_CASE_METHOD_SIG based test run that succeeds",
"[class][template][nttp]",
((int V), V),
1, 3, 6) {
REQUIRE(Nttp_Fixture<V>::value > 0);
}
template<typename T>
struct Template_Fixture_2 {
Template_Fixture_2() {}
T m_a;
};
template< typename T, size_t V>
struct Template_Foo_2 {
size_t size() { return V; }
};
TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG(
Template_Fixture_2,
"A TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG based test run that succeeds",
"[class][template][product][nttp]",
((typename T, size_t S), T, S),
(std::array, Template_Foo_2),
((int,2), (float,6))) {
REQUIRE(Template_Fixture_2<TestType>{}.m_a.size() >= 2);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Template fixtures with types specified in template type lists
Catch2 also provides TEMPLATE_LIST_TEST_CASE_METHOD
to support template fixtures with types specified in template type lists like std::tuple
, boost::mpl::list
or boost::mp11::mp_list
. This test case works the same as TEMPLATE_TEST_CASE_METHOD
, only difference is the source of types. This allows you to reuse the template type list in multiple test cases.
Example:
using MyTypes = std::tuple<int, char, double>;
TEMPLATE_LIST_TEST_CASE_METHOD(Template_Fixture,
"Template test case method with test types specified inside std::tuple",
"[class][template][list]",
MyTypes) {
REQUIRE( Template_Fixture<TestType>::m_a == 1 );
}
1
2
3
4
5
6
7
2
3
4
5
6
7