blob: e1cb7829e44120c107758e87c8f366e0986d2627 [file] [log] [blame]
onqtam8126b562016-05-27 17:01:15 +03001<!DOCTYPE html>
2<html>
3<title>tutorial</title>
4<xmp theme="united" style="display:none;">
5
6## Tutorial
7
8To get started with **doctest** all you need is to download the [**latest version**](https://raw.githubusercontent.com/onqtam/doctest/master/doctest/doctest.h) which is just a single header and include it in your source files (or add this repository as a git submodule).
9
10This tutorial assumes you can use the header directly: ```#include "doctest.h"``` - so it is either in the same folder with your test source files or you have set up the include paths to it in your build system properly.
11
12[TDD](https://en.wikipedia.org/wiki/Test-driven_development) is not discussed in this tutorial.
13
14## A simple example
15
16Suppose we have a ```factorial()``` function that we want to test:
17
18```
19int factorial(int number) { return number <= 1 ? number : factorial(number - 1) * number; }
20```
21
22A complete compiling example with a self-registering test looks like this:
23
24```
25#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
26#include "doctest.h"
27
28int factorial(int number) { return number <= 1 ? number : factorial(number - 1) * number; }
29
30TEST_CASE("testing the factorial function") {
31 CHECK(factorial(1) == 1);
32 CHECK(factorial(2) == 2);
33 CHECK(factorial(3) == 6);
34 CHECK(factorial(10) == 3628800);
35}
36```
37
38This will compile to a complete executable which responds to command line arguments. If you just run it with no arguments it will execute all test cases (in this case - just one), report any failures, report a summary of how many tests passed and failed and returns 0 on success and 1 if anything failed (useful if you just want a yes/no answer to: "did it work").
39
40If you run this as written it will pass. Everything is good. Right? Well there is still a bug here. We missed to check if ```factorial(0) == 1``` so lets add that check as well:
41
42```
43TEST_CASE("testing the factorial function") {
44 CHECK(factorial(0) == 1);
45 CHECK(factorial(1) == 1);
46 CHECK(factorial(2) == 2);
47 CHECK(factorial(3) == 6);
48 CHECK(factorial(10) == 3628800);
49}
50```
51
52Now we get a failure - something like:
53
54```
55test.cpp(7) FAILED!
56 CHECK( factorial(0) == 1 )
57with expansion:
58 CHECK( 0 == 1 )
59```
60
61Note 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 let's us immediately see what the problem is.
62
63Let's change the factorial function to:
64
65```
66int factorial(int number) { return number > 1 ? factorial(number - 1) * number : 1; }
67```
68
69Now all the tests pass.
70
71Of course there are still more issues to do deal with. For example we'll hit problems when the return value starts to exceed the range of an 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.
72
73## What did we do here?
74
75Although this was a simple test it's been enough to demonstrate a few things about how **doctest** is used.
76
771. 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. You can only use that ```#define``` in one source file for (hopefully) obvious reasons. Once you have more than one file with unit tests in you'll just ```#include "doctest.h"``` and go. Usually it's a good idea to have a dedicated implementation file that just has ```#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN``` and ```#include "doctest.h"```. You can also provide your own implementation of main and drive **doctest** yourself - see [**supplying your own ```main()```**](main.html).
782. We introduce test cases with the ```TEST_CASE``` macro. It takes one argument - a free form test name (for more see [**Test cases and subcases**](testcases.html)). The test name doesn't have to be unique. You can run sets of tests by specifying a wildcarded test name or a tag expression. See the [**command line**](commandline.html) docs for more information on running tests.
793. The name is just a string. 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.
804. We write our individual test assertions using the ```CHECK()``` macro. Rather than a separate macro for each type of condition (equal, less than, greater than, etc.) we express the condition naturally using C++ syntax. Behind the scenes a simple expression template captures the left-hand-side and right-hand-side of the expression so we can display the values in our test report. There are other [**assertion macros**](assertions.html) not covered in this tutorial - but because of this technique the number of them is drastically reduced.
81
82## Test cases and subcases
83
84Most test frameworks have a class-based fixture mechanism - 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).
85
86While **doctest** 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 [**problems like these**](http://jamesnewkirk.typepad.com/posts/2007/09/why-you-should-.html) that led James Newkirk who led the team that built NUnit to start again from scratch and build [**xUnit**](http://jamesnewkirk.typepad.com/posts/2007/09/announcing-xuni.html)).
87
88**doctest** takes a different approach (to both NUnit and xUnit) that is a more natural fit for C++ and the C family of languages.
89
90This is best explained through an example:
91
92```
93TEST_CASE("vectors can be sized and resized") {
94 std::vector<int> v(5);
95
96 REQUIRE(v.size() == 5);
97 REQUIRE(v.capacity() >= 5);
98
99 SUBCASE("adding to the vector increases it's size") {
100 v.push_back(1);
101
102 CHECK(v.size() == 6);
103 CHECK(v.capacity() >= 6);
104 }
105 SUBCASE("reserving increases just the capacity") {
106 v.reserve(6);
107
108 CHECK(v.size() == 5);
109 CHECK(v.capacity() >= 6);
110 }
111}
112```
113
114For each ```SUBCASE()``` the ```TEST_CASE()``` is executed from the start - so as we enter each subcase we know that the size is 5 and the capacity is at least 5. We enforce those requirements with the ```REQUIRE()``` macros at the top level so we can be confident in them. If a ```CHECK()``` fails - the test is marked as failed but the execution continues - but if a ```REQUIRE()``` fails - execution of the test stops.
115
116This works because the ```SUBCASE()``` macro contains an if statement that calls back into **doctest** to see if the subcase should be executed. One leaf subcase is executed on each run through a ```TEST_CASE()```. The other subcases are skipped. Next time the next subcase is executed and so on until no new subcases are encountered.
117
118So 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. The power of subcases really shows when we start nesting them like in the example below:
119
120<table><tr><td>
121Code
122</td><td>
123Output
124</td></tr><tr><td>
125<pre lang="c++">
126#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
127#include "doctest.h"
onqtam375568c2017-05-17 04:19:58 +0300128<br>
onqtam8126b562016-05-27 17:01:15 +0300129#include &lt;iostream&gt;
130using namespace std;
onqtam375568c2017-05-17 04:19:58 +0300131<br>
onqtam8126b562016-05-27 17:01:15 +0300132TEST_CASE("lots of nested subcases") {
onqtam375568c2017-05-17 04:19:58 +0300133&nbsp;&nbsp;&nbsp;&nbsp;cout << endl << "root" << endl;
134&nbsp;&nbsp;&nbsp;&nbsp;SUBCASE("") {
135&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout << "1" << endl;
136&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUBCASE("") { cout << "1.1" << endl; }
137&nbsp;&nbsp;&nbsp;&nbsp;}
138&nbsp;&nbsp;&nbsp;&nbsp;SUBCASE("") {
139&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout << "2" << endl;
140&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUBCASE("") { cout << "2.1" << endl; }
141&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUBCASE("") {
142&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout << "2.2" << endl;
143&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUBCASE("") {
144&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout << "2.2.1" << endl;
145&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUBCASE("") { cout << "2.2.1.1" << endl; }
146&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUBCASE("") { cout << "2.2.1.2" << endl; }
147&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
148&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
149&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUBCASE("") { cout << "2.3" << endl; }
150&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SUBCASE("") { cout << "2.4" << endl; }
151&nbsp;&nbsp;&nbsp;&nbsp;}
onqtam8126b562016-05-27 17:01:15 +0300152}
153</pre>
onqtam375568c2017-05-17 04:19:58 +0300154</td><td width="400">
onqtam8126b562016-05-27 17:01:15 +0300155<pre lang="">
onqtam375568c2017-05-17 04:19:58 +0300156root
onqtam8126b562016-05-27 17:01:15 +03001571
onqtam375568c2017-05-17 04:19:58 +03001581.1<br>
onqtam8126b562016-05-27 17:01:15 +0300159root
1602
onqtam375568c2017-05-17 04:19:58 +03001612.1<br>
onqtam8126b562016-05-27 17:01:15 +0300162root
1632
1642.2
1652.2.1
onqtam375568c2017-05-17 04:19:58 +03001662.2.1.1<br>
onqtam8126b562016-05-27 17:01:15 +0300167root
1682
1692.2
1702.2.1
onqtam375568c2017-05-17 04:19:58 +03001712.2.1.2<br>
onqtam8126b562016-05-27 17:01:15 +0300172root
1732
onqtam375568c2017-05-17 04:19:58 +03001742.3<br>
onqtam8126b562016-05-27 17:01:15 +0300175root
1762
1772.4
178</pre>
179</td></tr></table>
180
181Subcases can be nested to an arbitrary depth (limited only by your stack size). Each leaf subcase (a subcase that contains no nested subcases) will be executed exactly once on a separate path of execution from any other leaf subcase (so no leaf subcase can interfere with another). A fatal failure in a parent subcase will prevent nested subcases from running - but then that's the idea.
182
onqtam8126b562016-05-27 17:01:15 +0300183## Scaling up
184
185To keep the tutorial simple we put all our code in a single file. This is fine to get started - and makes jumping into **doctest** even quicker and easier. This is not really the best approach when you start writing more real-world tests.
186
187The requirement is that the following block of code ([**or equivalent**](main.html)):
188
189```
190#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
191#include "doctest.h"
192```
193
194appears in _exactly_ one translation unit (source file). Use as many additional source files as you need for your tests - partitioned however makes most sense for your way of working. Each additional file needs only to ```#include "doctest.h"``` - do not repeat the ```#define```!
195
196In fact it is usually a good idea to put the block with the ```#define``` in it's own source file.
197
198## Next steps
199
200This has been a brief introduction to get you up and running with **doctest** and to point out some of the key differences between **doctest** 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.
201
202Of course there is more to learn - see the ever-growing [**reference**](readme.html#reference) section for what's available.
203
204---------------
205
206[Home](readme.html#reference)
207
208
209</xmp>
210<script src="strapdown.js/strapdown.js"></script>
211</html>