mirror of
https://github.com/catchorg/Catch2.git
synced 2025-08-07 14:44:45 +02:00
Fixed bug
54
Tutorial.md
54
Tutorial.md
@@ -16,20 +16,25 @@ Note that the full distribution also contains some project files and cpp files,
|
||||
|
||||
# Writing tests
|
||||
|
||||
Let's start with a really simple example. Say you have written a function to calculate factorials and now you want to test it (let's leave aside TDD for now). To keep things simple we'll put everything in a single file.
|
||||
Let's start with a really simple example. 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;
|
||||
}
|
||||
```
|
||||
|
||||
To keep things simple we'll put everything in a single file.
|
||||
|
||||
```c++
|
||||
#define CATCH_CONFIG_MAIN // This tell CATCH to provide a main() - only do this in one cpp file
|
||||
#include "catch.hpp"
|
||||
|
||||
unsigned int Factorial( unsigned int number )
|
||||
{
|
||||
unsigned int Factorial( unsigned int number ) {
|
||||
return number <= 1 ? number : Factorial(number-1)*number;
|
||||
}
|
||||
|
||||
TEST_CASE( "example/factorial", "The Factorial function should return the factorial of the number passed in" )
|
||||
{
|
||||
REQUIRE( Factorial(0) == 0 );
|
||||
TEST_CASE( "example/factorial", "The Factorial function should return the factorial of the number passed in" ) {
|
||||
REQUIRE( Factorial(1) == 1 );
|
||||
REQUIRE( Factorial(2) == 2 );
|
||||
REQUIRE( Factorial(3) == 6 );
|
||||
@@ -39,30 +44,43 @@ Let's start with a really simple example. Say you have written a function to cal
|
||||
|
||||
This will compile to a complete executable, which responds to [[command line parameters]]. 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").
|
||||
|
||||
Now the more awake among you may notice that the Factorial function will hit problems when the return value starts to exceed the range of an unsigned int. With factorials that can happen quite quickly. Assuming 32-bit ints the maximum value is 4,294,967,295 (actually there's another, more serious, problem that I honestly missed when writing this. I'll update more fully later - but for now have fun finding it!).
|
||||
If you run this as written it will pass. Everything is good. Right?
|
||||
Well, 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).
|
||||
|
||||
Let's add a few more test for this:
|
||||
What is the bug? Well what is the factorial of zero?
|
||||
[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!).
|
||||
|
||||
```c++
|
||||
TEST_CASE( "example/factorial", "The Factorial function should return the factorial of the number passed in" )
|
||||
{
|
||||
REQUIRE( Factorial(0) == 0 );
|
||||
Let's add that to the test case:
|
||||
|
||||
```C++
|
||||
TEST_CASE( "example/factorial", "The Factorial function should return the factorial of the number passed in" ) {
|
||||
REQUIRE( Factorial(0) == 1 );
|
||||
REQUIRE( Factorial(1) == 1 );
|
||||
REQUIRE( Factorial(2) == 2 );
|
||||
REQUIRE( Factorial(3) == 6 );
|
||||
REQUIRE( Factorial(10) == 3628800 );
|
||||
REQUIRE( Factorial(12) == 479001600 );
|
||||
REQUIRE( Factorial(13) == 6227020800 );
|
||||
}
|
||||
```
|
||||
|
||||
Your compiler will likely warn you about that last value (for 32 bit ints), but ignore that for now. Running this gives us this report:
|
||||
Now we get a failure - something like:
|
||||
|
||||
/Path/../example.cpp(16): Factorial(13) == 6227020800 failed for: 1932053504 == 6227020800
|
||||
```
|
||||
Example.cpp:291: Factorial(0) == 1 failed for: 0 == 1
|
||||
```
|
||||
|
||||
Note that we get the actual return value of Factorial(13) printed for us - even though we used a natural expression with the == operator.
|
||||
Note 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.
|
||||
|
||||
If we change the factorial function to take and return unsigned long instead (assuming 64 bit long) we should see this particular bug go away. Of course we have just pushed it out to a higher number, but it's up to the logic of your code to decide how to handle the overflow.
|
||||
Let's change the factorial function to:
|
||||
|
||||
```c++
|
||||
unsigned int Factorial( unsigned int number ) {
|
||||
return number > 1 ? Factorial(number-1)*number : 1;
|
||||
}
|
||||
```
|
||||
|
||||
Now all the tests pass.
|
||||
|
||||
There are other problems here - e.g. 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.
|
||||
|
||||
## What did we do here?
|
||||
|
||||
|
Reference in New Issue
Block a user