• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<a id="top"></a>
2# Tutorial
3
4**Contents**<br>
5[Getting Catch2](#getting-catch2)<br>
6[Where to put it?](#where-to-put-it)<br>
7[Writing tests](#writing-tests)<br>
8[Test cases and sections](#test-cases-and-sections)<br>
9[BDD-Style](#bdd-style)<br>
10[Scaling up](#scaling-up)<br>
11[Type parametrised test cases](#type-parametrised-test-cases)<br>
12[Next steps](#next-steps)<br>
13
14## Getting Catch2
15
16The simplest way to get Catch2 is to download the latest [single header version](https://raw.githubusercontent.com/catchorg/Catch2/master/single_include/catch2/catch.hpp). The single header is generated by merging a set of individual headers but it is still just normal source code in a header file.
17
18Alternative ways of getting Catch2 include using your system package
19manager, or installing it using [its CMake package](cmake-integration.md#installing-catch2-from-git-repository).
20
21The full source for Catch2, including test projects, documentation, and other things, is hosted on GitHub. [http://catch-lib.net](http://catch-lib.net) will redirect you there.
22
23
24## Where to put it?
25
26Catch2 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](https://levelofindirection.com/blog/unit-testing-in-cpp-and-objective-c-just-got-ridiculously-easier-still.html).
27
28The 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.
29
30_If you have installed Catch2 from system package manager, or CMake
31package, you need to include the header as `#include <catch2/catch.hpp>`_
32
33## Writing tests
34
35Let'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).
36
37```c++
38unsigned int Factorial( unsigned int number ) {
39    return number <= 1 ? number : Factorial(number-1)*number;
40}
41```
42
43To keep things simple we'll put everything in a single file (<a href="#scaling-up">see later for more on how to structure your test files</a>).
44
45```c++
46#define CATCH_CONFIG_MAIN  // This tells Catch to provide a main() - only do this in one cpp file
47#include "catch.hpp"
48
49unsigned int Factorial( unsigned int number ) {
50    return number <= 1 ? number : Factorial(number-1)*number;
51}
52
53TEST_CASE( "Factorials are computed", "[factorial]" ) {
54    REQUIRE( Factorial(1) == 1 );
55    REQUIRE( Factorial(2) == 2 );
56    REQUIRE( Factorial(3) == 6 );
57    REQUIRE( Factorial(10) == 3628800 );
58}
59```
60
61This will compile to a complete executable which responds to [command line arguments](command-line.md#top). If you just run it with no arguments it will execute all test cases (in this case there is just one), report any failures, report a summary of how many tests passed and failed and return the number of failed tests (useful for if you just want a yes/ no answer to: "did it work").
62
63If you run this as written it will pass. Everything is good. Right?
64Well, there is still a bug here. In fact the first version of this tutorial I posted here genuinely had the bug in! So it's not completely contrived (thanks to Daryle Walker (```@CTMacUser```) for pointing this out).
65
66What is the bug? Well what is the factorial of zero?
67[The factorial of zero is one](http://mathforum.org/library/drmath/view/57128.html) - which is just one of those things you have to know (and remember!).
68
69Let's add that to the test case:
70
71```c++
72TEST_CASE( "Factorials are computed", "[factorial]" ) {
73    REQUIRE( Factorial(0) == 1 );
74    REQUIRE( Factorial(1) == 1 );
75    REQUIRE( Factorial(2) == 2 );
76    REQUIRE( Factorial(3) == 6 );
77    REQUIRE( Factorial(10) == 3628800 );
78}
79```
80
81Now we get a failure - something like:
82
83```
84Example.cpp:9: FAILED:
85  REQUIRE( Factorial(0) == 1 )
86with expansion:
87  0 == 1
88```
89
90Note that we get the actual return value of Factorial(0) printed for us (0) - even though we used a natural expression with the == operator. That lets us immediately see what the problem is.
91
92Let's change the factorial function to:
93
94```c++
95unsigned int Factorial( unsigned int number ) {
96  return number > 1 ? Factorial(number-1)*number : 1;
97}
98```
99
100Now all the tests pass.
101
102Of course there are still more issues to deal with. For example we'll hit problems when the return value starts to exceed the range of an unsigned int. With factorials that can happen quite quickly. You might want to add tests for such cases and decide how to handle them. We'll stop short of doing that here.
103
104### What did we do here?
105
106Although this was a simple test it's been enough to demonstrate a few things about how Catch is used. Let's take a moment to consider those before we move on.
107
1081. All we did was ```#define``` one identifier and ```#include``` one header and we got everything - even an implementation of ```main()``` that will [respond to command line arguments](command-line.md#top). You can only use that ```#define``` in one implementation file, for (hopefully) obvious reasons. Once you have more than one file with unit tests in you'll just ```#include "catch.hpp"``` and go. Usually it's a good idea to have a dedicated implementation file that just has ```#define CATCH_CONFIG_MAIN``` and ```#include "catch.hpp"```. You can also provide your own implementation of main and drive Catch yourself (see [Supplying-your-own-main()](own-main.md#top)).
1092. We introduce test cases with the ```TEST_CASE``` macro. This macro takes one or two arguments - a free form test name and, optionally, one or more tags (for more see <a href="#test-cases-and-sections">Test cases and Sections</a>). The test name must be unique. You can run sets of tests by specifying a wildcarded test name or a tag expression. See the [command line docs](command-line.md#top) for more information on running tests.
1103. The name and tags arguments are just strings. We haven't had to declare a function or method - or explicitly register the test case anywhere. Behind the scenes a function with a generated name is defined for you, and automatically registered using static registry classes. By abstracting the function name away we can name our tests without the constraints of identifier names.
1114. We write our individual test assertions using the ```REQUIRE``` macro. Rather than a separate macro for each type of condition we express the condition naturally using C/C++ syntax. Behind the scenes a simple set of expression templates captures the left-hand-side and right-hand-side of the expression so we can display the values in our test report. As we'll see later there _are_ other assertion macros - but because of this technique the number of them is drastically reduced.
112
113<a id="test-cases-and-sections"></a>
114## Test cases and sections
115
116Most test frameworks have a class-based fixture mechanism. That is, test cases map to methods on a class and common setup and teardown can be performed in ```setup()``` and ```teardown()``` methods (or constructor/ destructor in languages, like C++, that support deterministic destruction).
117
118While Catch fully supports this way of working there are a few problems with the approach. In particular the way your code must be split up, and the blunt granularity of it, may cause problems. You can only have one setup/ teardown pair across a set of methods, but sometimes you want slightly different setup in each method, or you may even want several levels of setup (a concept which we will clarify later on in this tutorial). It was <a href="http://jamesnewkirk.typepad.com/posts/2007/09/why-you-should-.html">problems like these</a> that led James Newkirk, who led the team that built NUnit, to start again from scratch and <a href="http://jamesnewkirk.typepad.com/posts/2007/09/announcing-xuni.html">build xUnit</a>).
119
120Catch takes a different approach (to both NUnit and xUnit) that is a more natural fit for C++ and the C family of languages. This is best explained through an example ([code](../examples/100-Fix-Section.cpp)):
121
122```c++
123TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
124
125    std::vector<int> v( 5 );
126
127    REQUIRE( v.size() == 5 );
128    REQUIRE( v.capacity() >= 5 );
129
130    SECTION( "resizing bigger changes size and capacity" ) {
131        v.resize( 10 );
132
133        REQUIRE( v.size() == 10 );
134        REQUIRE( v.capacity() >= 10 );
135    }
136    SECTION( "resizing smaller changes size but not capacity" ) {
137        v.resize( 0 );
138
139        REQUIRE( v.size() == 0 );
140        REQUIRE( v.capacity() >= 5 );
141    }
142    SECTION( "reserving bigger changes capacity but not size" ) {
143        v.reserve( 10 );
144
145        REQUIRE( v.size() == 5 );
146        REQUIRE( v.capacity() >= 10 );
147    }
148    SECTION( "reserving smaller does not change size or capacity" ) {
149        v.reserve( 0 );
150
151        REQUIRE( v.size() == 5 );
152        REQUIRE( v.capacity() >= 5 );
153    }
154}
155```
156
157For each ```SECTION``` the ```TEST_CASE``` is executed from the start - so as we enter each section we know that size is 5 and capacity is at least 5. We enforced those requirements with the ```REQUIRE```s at the top level so we can be confident in them.
158This works because the ```SECTION``` macro contains an if statement that calls back into Catch to see if the section should be executed. One leaf section is executed on each run through a ```TEST_CASE```. The other sections are skipped. Next time through the next section is executed, and so on until no new sections are encountered.
159
160So far so good - this is already an improvement on the setup/teardown approach because now we see our setup code inline and use the stack.
161
162The power of sections really shows, however, when we need to execute a sequence of checked operations. Continuing the vector example, we might want to verify that attempting to reserve a capacity smaller than the current capacity of the vector changes nothing. We can do that, naturally, like so:
163
164```c++
165    SECTION( "reserving bigger changes capacity but not size" ) {
166        v.reserve( 10 );
167
168        REQUIRE( v.size() == 5 );
169        REQUIRE( v.capacity() >= 10 );
170
171        SECTION( "reserving smaller again does not change capacity" ) {
172            v.reserve( 7 );
173
174            REQUIRE( v.capacity() >= 10 );
175        }
176    }
177```
178
179Sections can be nested to an arbitrary depth (limited only by your stack size). Each leaf section (i.e. a section that contains no nested sections) will be executed exactly once, on a separate path of execution from any other leaf section (so no leaf section can interfere with another). A failure in a parent section will prevent nested sections from running - but then that's the idea.
180
181## BDD-Style
182
183If you name your test cases and sections appropriately you can achieve a BDD-style specification structure. This became such a useful way of working that first class support has been added to Catch. Scenarios can be specified using ```SCENARIO```, ```GIVEN```, ```WHEN``` and ```THEN``` macros, which map on to ```TEST_CASE```s and ```SECTION```s, respectively. For more details see [Test cases and sections](test-cases-and-sections.md#top).
184
185The vector example can be adjusted to use these macros like so ([example code](../examples/120-Bdd-ScenarioGivenWhenThen.cpp)):
186
187```c++
188SCENARIO( "vectors can be sized and resized", "[vector]" ) {
189
190    GIVEN( "A vector with some items" ) {
191        std::vector<int> v( 5 );
192
193        REQUIRE( v.size() == 5 );
194        REQUIRE( v.capacity() >= 5 );
195
196        WHEN( "the size is increased" ) {
197            v.resize( 10 );
198
199            THEN( "the size and capacity change" ) {
200                REQUIRE( v.size() == 10 );
201                REQUIRE( v.capacity() >= 10 );
202            }
203        }
204        WHEN( "the size is reduced" ) {
205            v.resize( 0 );
206
207            THEN( "the size changes but not capacity" ) {
208                REQUIRE( v.size() == 0 );
209                REQUIRE( v.capacity() >= 5 );
210            }
211        }
212        WHEN( "more capacity is reserved" ) {
213            v.reserve( 10 );
214
215            THEN( "the capacity changes but not the size" ) {
216                REQUIRE( v.size() == 5 );
217                REQUIRE( v.capacity() >= 10 );
218            }
219        }
220        WHEN( "less capacity is reserved" ) {
221            v.reserve( 0 );
222
223            THEN( "neither size nor capacity are changed" ) {
224                REQUIRE( v.size() == 5 );
225                REQUIRE( v.capacity() >= 5 );
226            }
227        }
228    }
229}
230```
231
232Conveniently, these tests will be reported as follows when run:
233
234```
235Scenario: vectors can be sized and resized
236     Given: A vector with some items
237      When: more capacity is reserved
238      Then: the capacity changes but not the size
239```
240
241<a id="scaling-up"></a>
242## Scaling up
243
244To keep the tutorial simple we put all our code in a single file. This is fine to get started - and makes jumping into Catch even quicker and easier. As you write more real-world tests, though, this is not really the best approach.
245
246The requirement is that the following block of code ([or equivalent](own-main.md#top)):
247
248```c++
249#define CATCH_CONFIG_MAIN
250#include "catch.hpp"
251```
252
253appears in _exactly one_ source file. Use as many additional cpp files (or whatever you call your implementation files) as you need for your tests, partitioned however makes most sense for your way of working. Each additional file need only ```#include "catch.hpp"``` - do not repeat the ```#define```!
254
255In fact it is usually a good idea to put the block with the ```#define``` [in its own source file](slow-compiles.md#top) (code example [main](../examples/020-TestCase-1.cpp), [tests](../examples/020-TestCase-2.cpp)).
256
257Do not write your tests in header files!
258
259
260## Type parametrised test cases
261
262Test cases in Catch2 can be also parametrised by type, via the
263`TEMPLATE_TEST_CASE` and `TEMPLATE_PRODUCT_TEST_CASE` macros,
264which behave in the same way the `TEST_CASE` macro, but are run for
265every type or type combination.
266
267For more details, see our documentation on [test cases and
268sections](test-cases-and-sections.md#type-parametrised-test-cases).
269
270
271## Next steps
272
273This 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.
274
275Of course there is more to learn - most of which you should be able to page-fault in as you go. Please see the ever-growing [Reference section](Readme.md#top) for what's available.
276
277---
278
279[Home](Readme.md#top)
280