Repeaters
Repeated run of suites or test cases
Full source code of the example
The OTest2 framework offers a simple way how to run one test case several times with different data. Let’s get a simple example:
#include <otest2/otest2.h>
#include <otest2/repeatervaluesimpl.h>
TEST_SUITE(RepeaterSuite) {
TEST_CASE(ValueRepeater) {
::OTest2::RepeaterValue<int> repeater{1, 2, 3, 5, 8, 13, 21};
TEST_SIMPLE() {
std::cout << "repeated case " << repeater.getIndex() << ": " << repeater.getValue() << std::endl;
}
}
}
If you run this test you’ll get similar output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
=============================== RepeaterSuite ================================
repeated case 0: 1
ValueRepeater (run: 1) [Passed]
repeated case 1: 2
ValueRepeater (run: 2) [Passed]
repeated case 2: 3
ValueRepeater (run: 3) [Passed]
repeated case 3: 5
ValueRepeater (run: 4) [Passed]
repeated case 4: 8
ValueRepeater (run: 5) [Passed]
repeated case 5: 13
ValueRepeater (run: 6) [Passed]
repeated case 6: 21
ValueRepeater (run: 7) [Passed]
------------------------------------------------------------------------------
Suite total [Passed]
================================ Test results ================================
Passed Failed Total
Suites 1 0 1
Cases 7 0 7
Checks 0 0 0
Errors 0
Test total [Passed]
==============================================================================
As you can see the test case were repeated for each of the values specified in the initializer of repeater value.
A list of values is not the only one possibility. One can implement custom repeater class. E.g. you have a list of communication nodes and you want to test sending of a message between each of the node pairs:
#include <otest2/repeater.h>
class RepeaterNodes : public Repeater {
private:
int size;
int left;
int right;
public:
/* -- just for the sake of the otest2 preprocessor */
explicit RepeaterNodes(
Runtime&);
explicit RepeaterNodes(
int size_) :
size(size_),
left(0),
right(0) {
/* -- empty size is not valid - at least one run is needed */
assert(size > 0);
}
std::pair<int, int> getPair() const noexcept {
return std::pair<int, int>(left, right);
}
virtual bool hasNextRun(
const Context& context_) const noexcept {
return left < size - 1 || right < size - 1;
}
static std::shared_ptr<RepeaterNodes> createNext(
const Context& context_,
std::shared_ptr<RepeaterNodes> current_,
Runtime& runtime_) {
if(current_ == nullptr) {
return std::make_shared<RepeaterNodes>(runtime_.nodes.size());
}
else {
if(current_->right < current_->size - 1)
++current_->right;
else {
current_->right = 0;
++current_->left;
}
return current_;
}
}
};
A repeater class must derive from the OTest2::Repeater
interface.
The static function createNextRun
is the main point of interest. This
factory function is invoked at the beginning of each run of the testing
object. The parameter current_
contains instance of the repeater object
used in previous run or nullptr
for the very first run. The function
optionally can accept other parameters which must be filled in the initializer
of the repeater fixture.
The virtual method hasNextRun()
must return false
if the last item is
the current one stopping so another run of the testing object.
The first constructor is not implemented and it’s present just to keep satisfied
the OTest2 preprocessor. Its parameters must be exactly the same as
the additional parameters of the createNextRun
static function.
The repeater class is then used quite straightforwardly:
TEST_SUITE(RepeaterSuite) {
TEST_CASE(RepeaterNodesCase) {
Runtime runtime;
RepeaterNodes repeater(runtime);
TEST_SIMPLE() {
auto node_pair_(repeater.getPair());
runtime.nodes[node_pair_.first]->sendFrom(
runtime.nodes[node_pair_.second].get());
}
}
}
with similar output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
=============================== RepeaterSuite ================================
0: a node 0 contacted me
RepeaterNodesCase (run: 1) [Passed]
0: a node 1 contacted me
RepeaterNodesCase (run: 2) [Passed]
0: a node 2 contacted me
RepeaterNodesCase (run: 3) [Passed]
1: a node 0 contacted me
RepeaterNodesCase (run: 4) [Passed]
1: a node 1 contacted me
RepeaterNodesCase (run: 5) [Passed]
1: a node 2 contacted me
RepeaterNodesCase (run: 6) [Passed]
2: a node 0 contacted me
RepeaterNodesCase (run: 7) [Passed]
2: a node 1 contacted me
RepeaterNodesCase (run: 8) [Passed]
2: a node 2 contacted me
RepeaterNodesCase (run: 9) [Passed]
------------------------------------------------------------------------------
Suite total [Passed]
================================ Test results ================================
Passed Failed Total
Suites 1 0 1
Cases 9 0 9
Checks 0 0 0
Errors 0
Test total [Passed]
==============================================================================