aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/catch2/docs/tutorial.md
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/catch2/docs/tutorial.md')
-rw-r--r--contrib/catch2/docs/tutorial.md228
1 files changed, 228 insertions, 0 deletions
diff --git a/contrib/catch2/docs/tutorial.md b/contrib/catch2/docs/tutorial.md
new file mode 100644
index 0000000..fb5a5b3
--- /dev/null
+++ b/contrib/catch2/docs/tutorial.md
@@ -0,0 +1,228 @@
+<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)