In a school assignment, I should write blackbox test for a method that returns true
for a parameter < 80 and false
otherwise. Currently my approach would be
for (int i = 0; i < 80; i++) {
assertTrue(someMethod(i));
}
for (int i = 80; i <= 100; i++) {
assertFalse(someMethod(i));
}
However, this would require 100 seperate assertions. Is there a best/better practice method? If relevant, I'm using JUnit 5 but could switch to JUnit 4 if required (it's just a school assignment after all). Regards.
For JUnit 5 consider the repeated test feature:
https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests
For your case you could repeat 100 times:
@ParameterizedTest
@MethodSource("args")
public void so(int argument)
{
assertTrue((argument < 80) == someMethod(argument));
}
private static IntStream args()
{
return IntStream.range(0, 100);
}
I would agree checking 1 - 100 is not totally necessary, just check around 80 (79, 80, 81). The only other case that might be worthwhile is checking a negative number but even that seems overkill in this case.
If you do decide to just check 79,80,81 then the ValueSource
annotation is cleaner:
@ParameterizedTest
@ValueSource(ints = { 79, 80, 81 })
public void so(int argument)
{
assertTrue((argument < 80) == someMethod(argument));
}
You'd usually be fine with just testing the edge cases, and maybe one additional representative of one of the ranges, eg
assertTrue(someMethod(79));
assertFalse(someMethod(80));
// not reaaaally necessary
assertTrue(someMethod(50));
assertFalse(someMethod(100));
In your case, you might also want to add the cutoff as a constant (eg static final int THRESHOLD = 80
) and use it in your test cases; this way it's easier to change if the threshold changes.
What you could do (in JUnit5) is the following:
Write (at least) three test cases that cover the three main use cases, those are an input < 80
, an input > 80
and the input = 80
.
It would be looking like this:
@Test
@DisplayName("[< 80]")
@Tag("below_eighty")
void numberBelowEightyTest(TestInfo testInfo) {
int number = 79;
assertTrue(someMethod(number));
}
@Test
@DisplayName("[= 80]")
@Tag("equals_eighty")
void numberEqualsEightyTest(TestInfo testInfo) {
int number = 80;
assertFalse(someMethod(number));
}
@Test
@DisplayName("[> 80]")
@Tag("above_eighty")
void numberAboveEightyTest(TestInfo testInfo) {
int number = 81;
assertFalse(someMethod(number));
}
Having tested those three use cases, you can be sure for all remaining numbers due to having tested the border directly as well as the nearest neighbours.
In case someone using JUnit 4:
@RunWith(Parameterized.class)
public class PerformanceStatusTest {
@Parameterized.Parameters
public static List<Integer> data() {
return IntStream.range(0, 100)
.boxed()
.collect(Collectors.toList());
}
private int testValue;
public PerformanceStatusTest(final int testValue) {
this.testValue = testValue;
}
@Test
public void someMethodTest() {
assertTrue((testValue < 80) == someMethod(testValue));
}
}
To mention another option which will - in this simple case - do full range checking: Use property-based testing with jqwik on the JUnit 5 platform:
import org.junit.jupiter.api.*;
import net.jqwik.api.*;
import net.jqwik.api.constraints.*;
class PartitionedFunctionProperty {
@Property
void below80returnTrue(@ForAll @IntRange(min= 0, max = 79) int aNumber) {
Assertions.assertTrue(someMethod(aNumber));
}
@Property
void from80returnFalse(@ForAll @IntRange(min = 80, max = 100) int aNumber) {
Assertions.assertFalse(someMethod(aNumber));
}
private boolean someMethod(int aNumber) {
if (aNumber < 80) return true;
return false;
}
}
If you want to really see that the full range is really being generated, add
annotation @Report(Reporting.GENERATED)
to the property method and you'll get the following output:
timestamp = 2018-12-05T14:50:36.668, generated = [80]
timestamp = 2018-12-05T14:50:36.671, generated = [81]
timestamp = 2018-12-05T14:50:36.672, generated = [82]
timestamp = 2018-12-05T14:50:36.672, generated = [83]
...
timestamp = 2018-12-05T14:50:36.676, generated = [98]
timestamp = 2018-12-05T14:50:36.676, generated = [99]
timestamp = 2018-12-05T14:50:36.677, generated = [100]
timestamp = 2018-12-05T14:50:36.679
tries = 21
checks = 21
generation-mode = EXHAUSTIVE
after-failure = SAMPLE_ONLY
seed = 4490524914178941008
Find the full working example on github.
来源:https://stackoverflow.com/questions/53597020/best-practice-for-looped-junit-test