Reputation: 10908
I'm currently doing my first Java project and like to fully TDD it. I'm using JUnit for writing the tests. Apparently JUnit does not provide support for data providers, which makes it rather annoying to test the same method with 20 different versions of an argument. What is the most popular/standard testing tool for Java that does support data providers? I came across TestNG, but have no idea how popular that one is, or how it compares to alternatives.
If there is a way to get this behaviour is a nice way using JUnit, then that might also work.
Upvotes: 43
Views: 81853
Reputation: 130
You can use https://genthz.org/ framework for test data generation.
Sample:
public class User {
private Person person;
private String login;
private String password;
}
public class Person {
protected String name;
protected String lastName;
protected Date birthday;
private IdCard idCard;
}
User value = new DashaDsl() {
{
// Generate value for name fiedl of Persone class.
path("person/name")
// Set custom instance builder for field name of Person class.
.simple(ctx -> "Alex");
}
// Use defaults configuration such as int, java.lang.Stirng and etc.
}.def()
// Get ObjectFactory
.objectFactory()
// Generate Person class object
.get(User.class);
Upvotes: 0
Reputation: 50231
Here is another option. You don't have to use Google Guava, that is just my implementation.
This uses the same @Parameters
as @dkatzel's answer, but instead of the class taking the arguments, the @Parameters
annotation goes on specific test methods, so you can pick and choose which methods use that set of arguments.
import java.util.Collection;
import com.google.common.collect.ImmutableList;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(JUnitParamsRunner.class)
public class FrobTester {
@SuppressWarnings("unused")
private Collection validfrobAndGorpValues() {
return ImmutableList.of(
new Object[] {"frob28953", 28953},
new Object[] {"oldfrob-189-255", 1890255}
);
}
@Test
@Parameters(method = "validfrobAndGorpValues")
public void whenGivenFrobString_thenGorpIsCorrect(
String frobString,
int expectedGorpValue
) {
// Arrange
Frob frob = new Frob(frobString);
// Act
var actualGorpValue = frob.getGorpValue();
// Assert
Assert.assertEquals(actualGorpValue, expectedGorpValue);
}
}
Upvotes: 4
Reputation: 3149
You can use JUnit 5's ParameterizedTest. Here's an example from https://www.petrikainulainen.net/programming/testing/junit-5-tutorial-writing-parameterized-tests/ :
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
@DisplayName("Should pass the method parameters provided by the sumProvider() method")
class MethodSourceExampleTest {
@DisplayName("Should calculate the correct sum")
@ParameterizedTest(name = "{index} => a={0}, b={1}, sum={2}")
@MethodSource("sumProvider")
void sum(int a, int b, int sum) {
assertEquals(sum, a + b);
}
private static Stream<Arguments> sumProvider() {
return Stream.of(
Arguments.of(1, 1, 2),
Arguments.of(2, 3, 5)
);
}
}
It's possible to load test parameters from an annotation, a method or even a CSV file.
Upvotes: 9
Reputation: 20043
Coworkers of mine at our company wrote a freely available DataProvider in TestNG style for JUnit which you can find on github (https://github.com/TNG/junit-dataprovider).
We use it in very large projects and it works just fine for us. It has some advantages over JUnit's Parameterized
as it will reduce the overhead of separate classes and you can execute single tests as well.
An example looks something like this
@DataProvider
public static Object[][] provideStringAndExpectedLength() {
return new Object[][] {
{ "Hello World", 11 },
{ "Foo", 3 }
};
}
@Test
@UseDataProvider( "provideStringAndExpectedLength" )
public void testCalculateLength( String input, int expectedLength ) {
assertThat( calculateLength( input ) ).isEqualTo( expectedLength );
}
Edit: Since v1.7, it also supports other ways to provide data (strings, lists) and can inline the provider so that a separate method is not necessarily needed.
A full, working example can be found on the manual page on github. It also has a few more features, like collecting the providers in utility classes and accessing them from other classes etc. The manual page is very detailed, I'm sure you'll find any questions answered there.
Upvotes: 56
Reputation: 14540
Depending on your needs in flexibility vs readability, you can choose Parameterized
- junit's built in option, described by dkatzel. Other options are external junit runners provided by external libraries like zohhak, which let's you do:
@TestWith({
"clerk, 45'000 USD, GOLD",
"supervisor, 60'000 GBP, PLATINUM"
})
public void canAcceptDebit(Employee employee, Money money, ClientType clientType) {
assertTrue( employee.canAcceptDebit(money, clientType) );
}
or junitParams with a bit different functionality. just pick whatever suits you the most
Upvotes: 10
Reputation: 31648
JUnit 4 has parameterized test which is the does the same thing as php data providers
@RunWith(Parameterized.class)
public class MyTest{
@Parameters
public static Collection<Object[]> data() {
/*create and return a Collection
of Objects arrays here.
Each element in each array is
a parameter to your constructor.
*/
}
private int a,b,c;
public MyTest(int a, int b, int c) {
this.a= a;
this.b = b;
this.c = c;
}
@Test
public void test() {
//do your test with a,b
}
@Test
public void testC(){
//you can have multiple tests
//which all will run
//...test c
}
}
Upvotes: 41