this part is mainly around tools usable with JUnit. You can use most of these techniques with TestNG as well, check out the documentation if you need to use TestNG. |
Parameterized tests
This is a great solution to repeat the same test multiple times. Overall idea
is to define a test scenario (I test function F
) and to make the input/output data
dynamic.
JUnit 4
Here is an example. Let’s assume we have this test which validates the connection URI using ConnectionService
:
public class MyConnectionURITest {
@Test
public void checkMySQL() {
assertTrue(new ConnectionService().isValid("jdbc:mysql://localhost:3306/mysql"));
}
@Test
public void checkOracle() {
assertTrue(new ConnectionService().isValid("jdbc:oracle:thin:@//myhost:1521/oracle"));
}
}
We clearly identify the test method is always the same except the value. It can therefore be rewritter
using JUnit Parameterized
runner like that:
@RunWith(Parameterized.class) (1)
public class MyConnectionURITest {
@Parameterized.Parameters(name = "{0}") (2)
public static Iterable<String> uris() { (3)
return asList(
"jdbc:mysql://localhost:3306/mysql",
"jdbc:oracle:thin:@//myhost:1521/oracle");
}
@Parameterized.Parameter (4)
public String uri;
@Test
public void isValid() { (5)
assertNotNull(uri);
}
}
1 | Parameterized is the runner understanding @Parameters and how to use it. Note that you can generate random data here if desired. |
2 | by default the name of the executed test is the index of the data, here we customize it using the first parameter toString() value to have something more readable |
3 | the @Parameters method MUST be static and return an array or iterable of the data used by the tests |
4 | you can then inject the current data using @Parameter annotation, it can take a parameter if you use an array of array instead of an iterable of object in @Parameterized and you can select which item you want injected this way |
5 | the @Test method will be executed using the contextual data, in this sample we’ll get executed twice with the 2 specified urls |
you don’t have to define a single @Test method, if you define multiple, each of them will be executed with all the data (ie if we add a test in previous example you will get 4 tests execution - 2 per data, ie 2x2)
|
JUnit 5
JUnit 5 reworked this feature to make it way easier to use. The full documentation is available at junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests.
The main difference is you can also define inline on the test method that it is a parameterized test and which are the values:
@ParameterizedTest
@ValueSource(strings = { "racecar", "radar", "able was I ere I saw elba" })
void mytest(String currentValue) {
// do test
}
However you can still use the previous behavior using a method binding configuration:
@ParameterizedTest
@MethodSource("stringProvider")
void mytest(String currentValue) {
// do test
}
static Stream<String> stringProvider() {
return Stream.of("foo", "bar");
}
This last option allows you to inject any type of value - not only primitives - which is very common to define scenarii.
don’t forget to add junit-jupiter-params dependency to benefit from this feature.
|