OK, then we can now start to write test codes. RushCheck requires you to write assertion based test cases. An assertion of function (or method) consists of triple where inputs, guard conditions and a testing property block. Here is a templete of assertion:
RushCheck::Assertion.new(Class1, Class2, ...) do |var1, var2, ...|
# testing property block
# this block should return boolean value (true, false or nil)
# in Ruby
end
For example, suppose that we want to test the sort
method of the Array class. The following assertion is a simple test case:
ast_zero =
RushCheck::Assertion.new() do
[].sort == []
end
whether if we sort empty array the result is also empty. This assertion does not have any inputs and guards but only have the property block.
Let’s see another example: ast_one =
RushCheck::Assertion.new(Integer) do |x|
[x].sort == [x]
end
This assertion defines that we claim for any integer x
, an array [x]
is not changed after sorting. We can test the property 100 times:
irb> ast_one.verbose_check
1:
[-1]
2:
[-2]
... (snip) ...
99:
[6]
100:
[1]
OK, passed 100 tests.
true
irb> ast_one.check
OK, passed 100 tests.
true
irb>
RushCheck supports random testing such as above. We will see later how to change the number of test, how to change the distribution, etc. Here we learned two testing methods, verbose_check and check. ‘verbose_check’ displays every instances of test, on the other hand ‘check’ does not display inputs but only the result.
Next example shows how RushCheck displays the counter example. If an assertion is failed, then there is a counter example of the assertion.
ast_two =
RushCheck::Assertion.new(Integer, Integer) do |x, y|
[x, y].sort == [x, y]
end
The above test is failed sometimes and we can find the result after checking.
irb> ast_two.check
Falsifiable, after 3 tests:
[2, -1]
false
irb>
Here, the counter example [2, -1]
of the assertion is appeared. In fact, [2, -1]
.sort equals [-1, 2]
and does not equal [2, -1]
.
Sometimes, we need several pre-conditions for tests. For example, if we have a pre-condition x <= y
in the previous assertion, then the assertion should be succeeded. We can write pre-conditions as guards in the property block:
ast_two_sorted =
RushCheck::Assertion.new(Integer, Integer) do |x, y|
RushCheck::guard { x <= y }
[x, y].sort == [x, y]
end
irb> ast_two_sorted.check
OK, passed 100 tests.
true
irb>
Note that it is always assumed that the number of arguments of Assertion.new
must be equal to the number of variables of the block. (Until ver 0.3, experimentally the number of arguments can be differed, however from ver 0.4, they must be equal.)
The arguments of Assertion.new
corresponds to the variables of block one to one. We can have any number of guards in the property block. If the guard property does not hold in random testing, then the test is abort and try to take another random instances. We can imagine the following test sequences in ast_two_sorted
.
-
x, y = 1, 2
-> guard g is passed -> check the test block and succeed
-
x, y = 3, 1
-> guard g is failed and abort (not counted)
-
x, y = 2, 3
-> …
-
… (whether passed 100 tests or not)