Gerhard Bräunlich
January 2022
Tests have different scope.
Tests have different goals.
Not OK:
Running main() from gtest_main.cc
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from SolverTestSuite
[ RUN ] SolverTestSuite.solves_regular_linear_equation
../test/test_solvers.cpp:9: Failure
Expected equality of these values:
solve_linear_equation(1.0 / 3.0, 0.1)
Which is: -3.333333333333333
-0.29999999999999999
[ FAILED ] SolverTestSuite.solves_regular_linear_equation (0 ms)
[----------] 1 test from SolverTestSuite (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] SolverTestSuite.solves_regular_linear_equation
1 FAILED TEST
Software development is complex.
=> Rechecking manually not feasible
Write tests together with code.
🎵 If you liked it, then you shoulda put a test on it.
├── lib1
│ ├── CMakeLists.txt
│ ├── *.cpp
│ ├── include
│ │ └── lib1
│ │ └── *.h
│ └── test
│ ├── CMakeLists.txt
│ └── test_*.cpp
├── lib2
│ └── ...
├── ...
├── README.md
└── .gitignore
Start runner:
cmake --build build --target test
# or
cd build ; ctest # use "--output-on-failure" for verbose output
Test project solve_linear_equation/build
Start 1: test_solvers
1/1 Test #1: test_solvers .....................***Failed 0.01 sec
0% tests passed, 1 tests failed out of 1
Total Test time (real) = 0.01 sec
The following tests FAILED:
1 - test_solvers (Failed)
Errors while running CTest
Correct wrong order of k
and d
:
Restart runner:
Test project solve_linear_equation/build
Start 1: test_solvers
1/1 Test #1: test_solvers ..................... Passed 0.00 sec
100% tests passed, 0 tests failed out of 1
Total Test time (real) = 0.00 sec
Add test to SolverTestSuite
.
Restart runner:
Test project solve_linear_equation/build
Start 1: test_solvers
1/1 Test #1: test_solvers .....................***Failed 0.01 sec
0% tests passed, 1 tests failed out of 1
Total Test time (real) = 0.00 sec
The following tests FAILED:
1 - test_solvers (Failed)
Errors while running CTest
k=0
and d=0
?Verified Documentation.
Use suitable assertions.
EXPECT_DOUBLE_EQ
for floatsEXPECT_TRUE(a == b)
Write your tests first. (Clean Code)
Prepare for 1000s of tests.
Minimal maintenance.
Rerun to locate bugs.
Do the work once.
Write the test as soon as possible.
Given-When-Then Pattern. (Clean Code)
Given: Setup of environment
When: Execute what you want to test
Then: Check result
(if required): Cleanup
That’s why I chose 1/3
and 0.1
.
We could do the same thing here.
We use a nontrivial test fixture.
No need to copy and paste.
Use Fixtures.
You will be facing common challenges.
Break the vicious circle by adding integration tests.
I can’t test hidden/private code.
No problem, everybody else can’t, either.
I can’t test every combination of inputs.
Test until you are confident that your code works.
I don’t understand what a function does.
No problem, use unit testing.
The function has 20 parameters.
Unit testing tests atomic units.
The function needs to read a file.
#include <fstream>
#include <string>
std::string bad_function() {
std::ifstream input;
input.open("data.txt");
std::string content;
input >> content;
return content + content;
}
Split IO from processing!
Split IO from processing:
Might help in the “Interoperation” case.
More info: gMock.
Testing of higher level logic.
Example: run a Python script to orchestrate and check multiple binaries.
Unit Testing is not language-specific.
Correctness and more.