Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hard wrap tutorial doc for easier raw Markdown reading #2717

Open
wants to merge 1 commit into
base: devel
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
132 changes: 74 additions & 58 deletions docs/tutorial.md
Expand Up @@ -12,16 +12,20 @@

## 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`.
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`.


## 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++
unsigned int Factorial( unsigned int number ) {
Expand All @@ -44,7 +48,12 @@ TEST_CASE( "Factorials are computed", "[factorial]" ) {
}
```

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").
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
Expand All @@ -61,8 +70,8 @@ TEST_CASE( "Factorials are computed", "[factorial]" ) {
}
```

After another compile & run cycle, we will see a test failure. The output
will look something like:
After another compile & run cycle, we will see a test failure. The
output will look something like:

```
Example.cpp:9: FAILED:
Expand All @@ -71,11 +80,12 @@ 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`.
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;
Expand All @@ -86,36 +96,38 @@ unsigned int Factorial( unsigned int number ) {
### 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
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
* 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)).
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)._
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.
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.
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.
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)):
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]" ) {
Expand Down Expand Up @@ -152,17 +164,18 @@ TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
}
```

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. Each run through a test
case will execute one, and only one, leaf section.
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. 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
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:
`std::vector::reserve` does not remove unused excess capacity, like
this:

```cpp
SECTION( "reserving bigger changes capacity but not size" ) {
Expand All @@ -179,47 +192,50 @@ To continue on the vector example above, you could add a check that
```

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.
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.
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.
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).
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.
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).
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.
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.


---
Expand Down