122 lines
3.0 KiB
Plaintext
122 lines
3.0 KiB
Plaintext
When multiple tests differ only by a few hardcoded values they should be refactored as a single "parameterized" test. This reduces the chances of adding a bug and makes them more readable. Parameterized tests exist in most test frameworks (JUnit, TestNG, etc...).
|
|
|
|
|
|
The right balance needs of course to be found. There is no point in factorizing test methods when the parameterized version is a lot more complex than initial tests.
|
|
|
|
|
|
This rule raises an issue when at least 3 tests could be refactored as one parameterized test with less than 4 parameters. Only test methods which have at least one duplicated statement are considered.
|
|
|
|
|
|
== Noncompliant Code Example
|
|
|
|
with JUnit 5
|
|
|
|
[source,java]
|
|
----
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
public class AppTest
|
|
{
|
|
@Test
|
|
void test_not_null1() { // Noncompliant. The 3 following tests differ only by one hardcoded number.
|
|
setupTax();
|
|
assertNotNull(getTax(1));
|
|
}
|
|
|
|
@Test
|
|
void test_not_null2() {
|
|
setupTax();
|
|
assertNotNull(getTax(2));
|
|
}
|
|
|
|
@Test
|
|
void test_not_nul3l() {
|
|
setupTax();
|
|
assertNotNull(getTax(3));
|
|
}
|
|
|
|
@Test
|
|
void testLevel1() { // Noncompliant. The 3 following tests differ only by a few hardcoded numbers.
|
|
setLevel(1);
|
|
runGame();
|
|
assertEquals(playerHealth(), 100);
|
|
}
|
|
|
|
@Test
|
|
void testLevel2() { // Similar test
|
|
setLevel(2);
|
|
runGame();
|
|
assertEquals(playerHealth(), 200);
|
|
}
|
|
|
|
@Test
|
|
void testLevel3() { // Similar test
|
|
setLevel(3);
|
|
runGame();
|
|
assertEquals(playerHealth(), 300);
|
|
}
|
|
}
|
|
----
|
|
|
|
|
|
== Compliant Solution
|
|
|
|
[source,java]
|
|
----
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
|
import org.junit.jupiter.params.ParameterizedTest;
|
|
import org.junit.jupiter.params.provider.CsvSource;
|
|
|
|
public class AppTest
|
|
{
|
|
|
|
@ParameterizedTest
|
|
@ValueSource(ints = {1, 2, 3})
|
|
void test_not_null(int arg) {
|
|
setupTax();
|
|
assertNotNull(getTax(arg));
|
|
}
|
|
|
|
@ParameterizedTest
|
|
@CsvSource({
|
|
"1, 100",
|
|
"2, 200",
|
|
"3, 300",
|
|
})
|
|
void testLevels(int level, int health) {
|
|
setLevel(level);
|
|
runGame();
|
|
assertEquals(playerHealth(), health);
|
|
}
|
|
}
|
|
----
|
|
|
|
|
|
== See
|
|
|
|
* https://phauer.com/2019/modern-best-practices-testing-java/#use-parameterized-tests[Modern Best Practices for Testing in Java - Philipp Hauer]
|
|
* https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests[JUnit 5 documentation - Parameterized tests]
|
|
* https://www.testwithspring.com/lesson/writing-parameterized-tests-with-junit-4/[Writing Parameterized Tests With JUnit 4]
|
|
* https://testng.org/doc/documentation-main.html#parameters[TestNG documentation - Parameters]
|
|
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
include::message.adoc[]
|
|
|
|
include::highlighting.adoc[]
|
|
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
include::comments-and-links.adoc[]
|
|
endif::env-github,rspecator-view[]
|