mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-04 00:51:52 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			229 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
<a id="top"></a>
 | 
						|
# Tutorial
 | 
						|
 | 
						|
**Contents**<br>
 | 
						|
[Getting Catch2](#getting-catch2)<br>
 | 
						|
[Writing tests](#writing-tests)<br>
 | 
						|
[Test cases and sections](#test-cases-and-sections)<br>
 | 
						|
[BDD style testing](#bdd-style-testing)<br>
 | 
						|
[Data and Type driven tests](#data-and-type-driven-tests)<br>
 | 
						|
[Next steps](#next-steps)<br>
 | 
						|
 | 
						|
 | 
						|
## Getting Catch2
 | 
						|
 | 
						|
Ideally you should be using Catch2 through its [CMake integration](cmake-integration.md#top).
 | 
						|
Catch2 also provides pkg-config files and two file (header + cpp)
 | 
						|
distribution, but this documentation will assume you are using CMake. If
 | 
						|
you are using the two file distribution instead, remember to replace
 | 
						|
the included header with `catch_amalgamated.hpp` ([step by step instructions](migrate-v2-to-v3.md#how-to-migrate-projects-from-v2-to-v3)).
 | 
						|
 | 
						|
 | 
						|
## 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).
 | 
						|
 | 
						|
```c++
 | 
						|
unsigned int Factorial( unsigned int number ) {
 | 
						|
    return number <= 1 ? number : Factorial(number-1)*number;
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
```c++
 | 
						|
#include <catch2/catch_test_macros.hpp>
 | 
						|
 | 
						|
unsigned int Factorial( unsigned int number ) {
 | 
						|
    return number <= 1 ? number : Factorial(number-1)*number;
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE( "Factorials are computed", "[factorial]" ) {
 | 
						|
    REQUIRE( Factorial(1) == 1 );
 | 
						|
    REQUIRE( Factorial(2) == 2 );
 | 
						|
    REQUIRE( Factorial(3) == 6 );
 | 
						|
    REQUIRE( Factorial(10) == 3628800 );
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
This 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").
 | 
						|
 | 
						|
Anyway, as the tests above as written will pass, but there is a bug.
 | 
						|
The problem is that `Factorial(0)` should return 1 (due to [its
 | 
						|
definition](https://en.wikipedia.org/wiki/Factorial#Factorial_of_zero)).
 | 
						|
Let's add that as an assertion to the test case:
 | 
						|
 | 
						|
```c++
 | 
						|
TEST_CASE( "Factorials are computed", "[factorial]" ) {
 | 
						|
    REQUIRE( Factorial(0) == 1 );
 | 
						|
    REQUIRE( Factorial(1) == 1 );
 | 
						|
    REQUIRE( Factorial(2) == 2 );
 | 
						|
    REQUIRE( Factorial(3) == 6 );
 | 
						|
    REQUIRE( Factorial(10) == 3628800 );
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
After another compile & run cycle, we will see a test failure. The output
 | 
						|
will look something like:
 | 
						|
 | 
						|
```
 | 
						|
Example.cpp:9: FAILED:
 | 
						|
  REQUIRE( Factorial(0) == 1 )
 | 
						|
with expansion:
 | 
						|
  0 == 1
 | 
						|
```
 | 
						|
 | 
						|
Note that the output contains both the original expression,
 | 
						|
`REQUIRE( Factorial(0) == 1 )` and the actual value returned by the call
 | 
						|
to the `Factorial` function: `0`.
 | 
						|
 | 
						|
We can fix this bug by slightly modifying the `Factorial` function to:
 | 
						|
```c++
 | 
						|
unsigned int Factorial( unsigned int number ) {
 | 
						|
  return number > 1 ? Factorial(number-1)*number : 1;
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
 | 
						|
### What did we do here?
 | 
						|
 | 
						|
Although this was a simple test it's been enough to demonstrate a few
 | 
						|
things about how Catch2 is used. Let's take a moment to consider those
 | 
						|
before we move on.
 | 
						|
 | 
						|
* We introduce test cases with the `TEST_CASE` macro. This macro takes
 | 
						|
  one or two string arguments - a free form test name and, optionally,
 | 
						|
  one or more tags (for more see [Test cases and Sections](#test-cases-and-sections)).
 | 
						|
* The test automatically self-registers with the test runner, and user
 | 
						|
  does not have do anything more to ensure that it is picked up by the test
 | 
						|
  framework. _Note that you can run specific test, or set of tests,
 | 
						|
  through the [command line](command-line.md#top)._
 | 
						|
* The individual test assertions are written using the `REQUIRE` macro.
 | 
						|
  It accepts a boolean expression, and uses expression templates to
 | 
						|
  internally decompose it, so that it can be individually stringified
 | 
						|
  on test failure.
 | 
						|
 | 
						|
On the last point, note that there are more testing macros available,
 | 
						|
because not all useful checks can be expressed as a simple boolean
 | 
						|
expression. As an example, checking that an expression throws an exception
 | 
						|
is done with the `REQUIRE_THROWS` macro. More on that later.
 | 
						|
 | 
						|
 | 
						|
## Test cases and sections
 | 
						|
 | 
						|
Like most test frameworks, Catch2 supports a class-based fixture mechanism,
 | 
						|
where individual tests are methods on class and setup/teardown can be
 | 
						|
done in constructor/destructor of the type.
 | 
						|
 | 
						|
However, their use in Catch2 is rare, because idiomatic Catch2 tests
 | 
						|
instead use _sections_ to share setup and teardown code between test code.
 | 
						|
This is best explained through an example ([code](../examples/100-Fix-Section.cpp)):
 | 
						|
 | 
						|
```c++
 | 
						|
TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
 | 
						|
    // This setup will be done 4 times in total, once for each section
 | 
						|
    std::vector<int> 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( "reserving bigger changes capacity but not size" ) {
 | 
						|
        v.reserve( 10 );
 | 
						|
 | 
						|
        REQUIRE( v.size() == 5 );
 | 
						|
        REQUIRE( v.capacity() >= 10 );
 | 
						|
    }
 | 
						|
    SECTION( "reserving smaller does not change size or capacity" ) {
 | 
						|
        v.reserve( 0 );
 | 
						|
 | 
						|
        REQUIRE( v.size() == 5 );
 | 
						|
        REQUIRE( v.capacity() >= 5 );
 | 
						|
    }
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
For each `SECTION` the `TEST_CASE` is **executed from the start**. This means
 | 
						|
that each section is entered with a freshly constructed vector `v`, that
 | 
						|
we know has size 5 and capacity at least 5, because the two assertions
 | 
						|
are also checked before the section is entered. This behaviour may not be
 | 
						|
ideal for tests where setup is expensive. Each run through a test case will
 | 
						|
execute one, and only one, leaf section.
 | 
						|
 | 
						|
Section can also be nested, in which case the parent section can be
 | 
						|
entered multiple times, once for each leaf section. Nested sections are
 | 
						|
most useful when you have multiple tests that share part of the set up.
 | 
						|
To continue on the vector example above, you could add a check that
 | 
						|
`std::vector::reserve` does not remove unused excess capacity, like this:
 | 
						|
 | 
						|
```cpp
 | 
						|
    SECTION( "reserving bigger changes capacity but not size" ) {
 | 
						|
        v.reserve( 10 );
 | 
						|
 | 
						|
        REQUIRE( v.size() == 5 );
 | 
						|
        REQUIRE( v.capacity() >= 10 );
 | 
						|
        SECTION( "reserving down unused capacity does not change capacity" ) {
 | 
						|
            v.reserve( 7 );
 | 
						|
            REQUIRE( v.size() == 5 );
 | 
						|
            REQUIRE( v.capacity() >= 10 );
 | 
						|
        }
 | 
						|
    }
 | 
						|
```
 | 
						|
 | 
						|
Another way to look at sections is that they are a way to define a tree
 | 
						|
of paths through the test. Each section represents a node, and the final
 | 
						|
tree is walked in depth-first manner, with each path only visiting only
 | 
						|
one leaf node.
 | 
						|
 | 
						|
There is no practical limit on nesting sections, as long as your compiler
 | 
						|
can handle them, but keep in mind that overly nested sections can become
 | 
						|
unreadable. From experience, having section nest more than 3 levels is
 | 
						|
usually very hard to follow and not worth the removed duplication.
 | 
						|
 | 
						|
 | 
						|
## BDD style testing
 | 
						|
 | 
						|
Catch2 also provides some basic support for BDD-style testing. There are
 | 
						|
macro aliases for `TEST_CASE` and `SECTIONS` that you can use so that
 | 
						|
the resulting tests read as BDD spec. `SCENARIO` acts as a `TEST_CASE`
 | 
						|
with "Scenario: " name prefix. Then there are `GIVEN`, `WHEN`, `THEN`
 | 
						|
(and their variants with `AND_` prefix), which act as a `SECTION`,
 | 
						|
similarly prefixed with the macro name.
 | 
						|
 | 
						|
For more details on the macros look at the [test cases and
 | 
						|
sections](test-cases-and-sections.md#top) part of the reference docs,
 | 
						|
or at the [vector example done with BDD macros](../examples/120-Bdd-ScenarioGivenWhenThen.cpp).
 | 
						|
 | 
						|
 | 
						|
## Data and Type driven tests
 | 
						|
 | 
						|
Test cases in Catch2 can also be driven by types, input data, or both
 | 
						|
at the same time.
 | 
						|
 | 
						|
For more details look into the Catch2 reference, either at the
 | 
						|
[type parametrized test cases](test-cases-and-sections.md#type-parametrised-test-cases),
 | 
						|
or [data generators](generators.md#top).
 | 
						|
 | 
						|
 | 
						|
## Next steps
 | 
						|
 | 
						|
This page is a brief introduction to get you up and running with Catch2,
 | 
						|
and to show the basic features of Catch2. The features mentioned here
 | 
						|
can get you quite far, but there are many more. However, you can read
 | 
						|
about these as you go, in the ever-growing [reference section](Readme.md#top)
 | 
						|
of the documentation.
 | 
						|
 | 
						|
 | 
						|
---
 | 
						|
 | 
						|
[Home](Readme.md#top)
 |