Add documentation for templated tests

This commit is contained in:
Martin Hořeňovský 2018-11-16 19:39:42 +01:00
parent 2d906a92cb
commit 00d4f5d3c6
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
3 changed files with 117 additions and 17 deletions

View File

@ -86,6 +86,65 @@ When any of these macros are used the console reporter recognises them and forma
Other than the additional prefixes and the formatting in the console reporter these macros behave exactly as ```TEST_CASE```s and ```SECTION```s. As such there is nothing enforcing the correct sequencing of these macros - that's up to the programmer! Other than the additional prefixes and the formatting in the console reporter these macros behave exactly as ```TEST_CASE```s and ```SECTION```s. As such there is nothing enforcing the correct sequencing of these macros - that's up to the programmer!
## Type parametrised test cases
In addition to `TEST_CASE`s, Catch2 also supports test cases parametrised
by type, in the form of `TEMPLATE_TEST_CASE`.
* **TEMPLATE_TEST_CASE(** _test name_ , _tags_, _type1_, _type2_, ..., _typen_ **)**
_test name_ and _tag_ are exactly the same as they are in `TEST_CASE`,
with the difference that the tag string must be provided (however, it
can be empty). _type1_ through _typen_ is the list of types for which
this test case should run, and, inside the test code, the current type
is available as the `TestType` type.
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>)`.
Example:
```cpp
TEMPLATE_TEST_CASE( "vectors can be sized and resized", "[vector][template]", int, std::string, (std::tuple<int,float>) ) {
std::vector<TestType> v( 5 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
SECTION( "resizing bigger changes size and capacity" ) {
v.resize( 10 );
REQUIRE( v.size() == 10 );
REQUIRE( v.capacity() >= 10 );
}
SECTION( "resizing smaller changes size but not capacity" ) {
v.resize( 0 );
REQUIRE( v.size() == 0 );
REQUIRE( v.capacity() >= 5 );
SECTION( "We can use the 'swap trick' to reset the capacity" ) {
std::vector<TestType> empty;
empty.swap( v );
REQUIRE( v.capacity() == 0 );
}
}
SECTION( "reserving smaller does not change size or capacity" ) {
v.reserve( 0 );
REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 );
}
}
```
_While there is an upper limit on the number of types you can specify
in single `TEMPLATE_TEST_CASE`, the limit is very high and should not
be encountered in practice._
--- ---
[Home](Readme.md#top) [Home](Readme.md#top)

View File

@ -30,6 +30,36 @@ class UniqueTestsFixture {
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. 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` that can be used together
with templated fixtures to perform tests for multiple different types.
However, unlike `TEST_CASE_METHOD`, `TEMPLATE_TEST_CASE_METHOD` requires
the tag specification to be non-empty, as it is followed by further macros
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>)`.
Example:
```cpp
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 );
}
```
_While there is an upper limit on the number of types you can specify
in single `TEMPLATE_TEST_CASE`, the limit is very high and should not
be encountered in practice._
--- ---
[Home](Readme.md#top) [Home](Readme.md#top)

View File

@ -8,6 +8,7 @@
[Test cases and sections](#test-cases-and-sections)<br> [Test cases and sections](#test-cases-and-sections)<br>
[BDD-Style](#bdd-style)<br> [BDD-Style](#bdd-style)<br>
[Scaling up](#scaling-up)<br> [Scaling up](#scaling-up)<br>
[Type parametrised test cases](#type-parametrised-test-cases)<br>
[Next steps](#next-steps)<br> [Next steps](#next-steps)<br>
## Getting Catch2 ## Getting Catch2
@ -22,7 +23,7 @@ The full source for Catch2, including test projects, documentation, and other th
## Where to put it? ## Where to put it?
Catch2 is header only. All you need to do is drop the file somewhere reachable from your project - either in some central location you can set your header search path to find, or directly into your project tree itself! This is a particularly good option for other Open-Source projects that want to use Catch for their test suite. See [this blog entry for more on that](http://www.levelofindirection.com/journal/2011/5/27/unit-testing-in-c-and-objective-c-just-got-ridiculously-easi.html). Catch2 is header only. All you need to do is drop the file somewhere reachable from your project - either in some central location you can set your header search path to find, or directly into your project tree itself! This is a particularly good option for other Open-Source projects that want to use Catch for their test suite. See [this blog entry for more on that](http://www.levelofindirection.com/journal/2011/5/27/unit-testing-in-c-and-objective-c-just-got-ridiculously-easi.html).
The rest of this tutorial will assume that the Catch2 single-include header (or the include folder) is available unqualified - but you may need to prefix it with a folder name if necessary. The rest of this tutorial will assume that the Catch2 single-include header (or the include folder) is available unqualified - but you may need to prefix it with a folder name if necessary.
@ -31,7 +32,7 @@ package, you need to include the header as `#include <catch2/catch.hpp>`_
## Writing tests ## Writing tests
Let's start with a really simple example ([code](../examples/010-TestCase.cpp)). Say you have written a function to calculate factorials and now you want to test it (let's leave aside TDD for now). Let's start with a really simple example ([code](../examples/010-TestCase.cpp)). Say you have written a function to calculate factorials and now you want to test it (let's leave aside TDD for now).
```c++ ```c++
unsigned int Factorial( unsigned int number ) { unsigned int Factorial( unsigned int number ) {
@ -122,31 +123,31 @@ Catch takes a different approach (to both NUnit and xUnit) that is a more natura
TEST_CASE( "vectors can be sized and resized", "[vector]" ) { TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
std::vector<int> v( 5 ); std::vector<int> v( 5 );
REQUIRE( v.size() == 5 ); REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 ); REQUIRE( v.capacity() >= 5 );
SECTION( "resizing bigger changes size and capacity" ) { SECTION( "resizing bigger changes size and capacity" ) {
v.resize( 10 ); v.resize( 10 );
REQUIRE( v.size() == 10 ); REQUIRE( v.size() == 10 );
REQUIRE( v.capacity() >= 10 ); REQUIRE( v.capacity() >= 10 );
} }
SECTION( "resizing smaller changes size but not capacity" ) { SECTION( "resizing smaller changes size but not capacity" ) {
v.resize( 0 ); v.resize( 0 );
REQUIRE( v.size() == 0 ); REQUIRE( v.size() == 0 );
REQUIRE( v.capacity() >= 5 ); REQUIRE( v.capacity() >= 5 );
} }
SECTION( "reserving bigger changes capacity but not size" ) { SECTION( "reserving bigger changes capacity but not size" ) {
v.reserve( 10 ); v.reserve( 10 );
REQUIRE( v.size() == 5 ); REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 10 ); REQUIRE( v.capacity() >= 10 );
} }
SECTION( "reserving smaller does not change size or capacity" ) { SECTION( "reserving smaller does not change size or capacity" ) {
v.reserve( 0 ); v.reserve( 0 );
REQUIRE( v.size() == 5 ); REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 ); REQUIRE( v.capacity() >= 5 );
} }
@ -163,13 +164,13 @@ The power of sections really shows, however, when we need to execute a sequence
```c++ ```c++
SECTION( "reserving bigger changes capacity but not size" ) { SECTION( "reserving bigger changes capacity but not size" ) {
v.reserve( 10 ); v.reserve( 10 );
REQUIRE( v.size() == 5 ); REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 10 ); REQUIRE( v.capacity() >= 10 );
SECTION( "reserving smaller again does not change capacity" ) { SECTION( "reserving smaller again does not change capacity" ) {
v.reserve( 7 ); v.reserve( 7 );
REQUIRE( v.capacity() >= 10 ); REQUIRE( v.capacity() >= 10 );
} }
} }
@ -188,13 +189,13 @@ SCENARIO( "vectors can be sized and resized", "[vector]" ) {
GIVEN( "A vector with some items" ) { GIVEN( "A vector with some items" ) {
std::vector<int> v( 5 ); std::vector<int> v( 5 );
REQUIRE( v.size() == 5 ); REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 ); REQUIRE( v.capacity() >= 5 );
WHEN( "the size is increased" ) { WHEN( "the size is increased" ) {
v.resize( 10 ); v.resize( 10 );
THEN( "the size and capacity change" ) { THEN( "the size and capacity change" ) {
REQUIRE( v.size() == 10 ); REQUIRE( v.size() == 10 );
REQUIRE( v.capacity() >= 10 ); REQUIRE( v.capacity() >= 10 );
@ -202,7 +203,7 @@ SCENARIO( "vectors can be sized and resized", "[vector]" ) {
} }
WHEN( "the size is reduced" ) { WHEN( "the size is reduced" ) {
v.resize( 0 ); v.resize( 0 );
THEN( "the size changes but not capacity" ) { THEN( "the size changes but not capacity" ) {
REQUIRE( v.size() == 0 ); REQUIRE( v.size() == 0 );
REQUIRE( v.capacity() >= 5 ); REQUIRE( v.capacity() >= 5 );
@ -210,7 +211,7 @@ SCENARIO( "vectors can be sized and resized", "[vector]" ) {
} }
WHEN( "more capacity is reserved" ) { WHEN( "more capacity is reserved" ) {
v.reserve( 10 ); v.reserve( 10 );
THEN( "the capacity changes but not the size" ) { THEN( "the capacity changes but not the size" ) {
REQUIRE( v.size() == 5 ); REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 10 ); REQUIRE( v.capacity() >= 10 );
@ -218,7 +219,7 @@ SCENARIO( "vectors can be sized and resized", "[vector]" ) {
} }
WHEN( "less capacity is reserved" ) { WHEN( "less capacity is reserved" ) {
v.reserve( 0 ); v.reserve( 0 );
THEN( "neither size nor capacity are changed" ) { THEN( "neither size nor capacity are changed" ) {
REQUIRE( v.size() == 5 ); REQUIRE( v.size() == 5 );
REQUIRE( v.capacity() >= 5 ); REQUIRE( v.capacity() >= 5 );
@ -256,6 +257,16 @@ In fact it is usually a good idea to put the block with the ```#define``` [in it
Do not write your tests in header files! Do not write your tests in header files!
## Type parametrised test cases
Test cases in Catch2 can be also parametrised by type, via the
`TEMPLATE_TEST_CASE` macro, which behaves in the same way the `TEST_CASE`
macro, but is run for every type.
For more details, see our documentation on [test cases and sections]
(test-cases-and-sections.md#type-parametrised-test-cases).
## Next steps ## Next steps
This has been a brief introduction to get you up and running with Catch, and to point out some of the key differences between Catch and other frameworks you may already be familiar with. This will get you going quite far already and you are now in a position to dive in and write some tests. This has been a brief introduction to get you up and running with Catch, and to point out some of the key differences between Catch and other frameworks you may already be familiar with. This will get you going quite far already and you are now in a position to dive in and write some tests.