-
Notifications
You must be signed in to change notification settings - Fork 164
Features
**Disclaimer: JUnit5 provides almost all of the features listed below with a little different syntax. For details see Migration guides.
Below you can find code examples for all supported features. Browsing the integration tests you can find even more examples. Please have a look at the corresponding packages for Java and Groovy integration tests.
Since: v1.0.0
This was the first use case for Java and its native array syntax support:
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
@RunWith(DataProviderRunner.class)
public class DataProviderArraySyntaxTest {
@DataProvider
public static Object[][] dataProviderAdd() {
// @formatter:off
return new Object[][] {
{ 0, 0, 0 },
{ 1, 1, 2 },
/* ... */
};
// @formatter:on
}
@Test
@UseDataProvider("dataProviderAdd")
public void testAdd(int a, int b, int expected) {
// When:
int result = a + b;
// Then:
assertEquals(expected, result);
}
}
Please note that if you only have a single parameter test method, since v1.10.3 you can also use Object[]
instead.
Since: v1.7.0 and further customizable since v1.8.0
If you don't want to maintain two methods for the dataprovider and the test method, you can use the String
syntax. Here, instead of using @UseDataProvider
to point to a method providing test data, you directly
pass test data using @DataProvider
annotation and its #value()
method to provide an array of regex-separated String
s (via #splitBy()
; default ","
). After splitting, each String
value can be trimmed back by spaces (= "
"), tabs (= "\t
) and line-separator (= "\n
" or "\r
") (via #trimValues()
; default true
). The
resulting String
is then parsed to its corresponding type in the test method signature. All
- primitive types (e.g.
char
,boolean
,int
), - primitive wrapper types (e.g.
Long
,Double
), - case-sensitive
Enum
names, -
String
s, and - types having single-argument
String
constructor are supported. TheString
"null"
will be passed asnull
object or"null"
String
according to#convertNulls()
(defaulttrue
).
// @formatter:off
@Test
@DataProvider(value = {
" | 0",
"a | 1",
"abc | 3",
"veryLongString | 14",
}, splitBy = "\\|", trimValues = true)
// @formatter:on
public void testStringLength2(String str, int expectedLength) {
// Expect:
assertThat(str.length()).isEqualTo(expectedLength);
}
@Test
@DataProvider({ "null", "" })
public void testIsEmptyString2(String str) {
// When:
boolean isEmpty = (str == null) ? true : str.isEmpty();
// Then:
assertThat(isEmpty).isTrue();
}
For more information about the @DataProvider
options, see DataProvider.java.
You can also use the String
syntax in a separate @DataProvider
method:
@DataProvider
public static String[] dataProviderFileExistence() {
// @formatter:off
return new String[] {
"src, true",
"src/main, true",
"src/main/java/, true",
"src/test/java/, true",
"test, false",
};
// @formatter:on
}
@Test
@UseDataProvider("dataProviderFileExistence")
public void testFileExistence(File file, boolean expected) {
// Expect:
assertEquals(expected, file.exists());
}
This feature is inspired by JUnitParams and @janschaefer.
Since: v1.6.0
For other languages on the JVM which have native List
support, you can use junit-dataprovider's List
syntax.
Note: The below example is Groovy. This only makes sense if you are not able to use the very powerful Spock framework, e.g. see (#12).
Since: v1.10.3
You can also use List<Object>
if you only have a single parameter test method.
Since: v1.12.0
You can use any subclass of Iterable
instead of only List
for the inner and outer type. Be aware, though, that the order of the inner Iterable
is important, so Set
might not be a good choice. Also Object
is no longer necessary as element type. You can use anything as type checking is done once converting to the desired parameter types.
import static org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import com.tngtech.java.junit.dataprovider.*
@RunWith(DataProviderRunner)
class DataProviderTest {
@DataProvider
static List<List<Object>> dataProviderBooleanLogicAnd() {
// @formatter:off
return [
[ false, false, false ],
[ true, false, false ],
[ false, true, false ],
[ true, true, true ],
]
// @formatter:on
}
@Test
@UseDataProvider('dataProviderBooleanLogicAnd')
void 'test boolean logic for "and"'(op1, op2, expected) {
// Expect:
assert (op1 && op2) == expected
}
}
Since: v1.12.0
The ability to provide custom resolvers to find proper dataprovider methods is added. The current logic was moved to DefaultDataProviderMethodResolver
which is the used default implementation. This means the code is fully backwards compatible. See also sections Change @DataProvider
location and Convention over configuration for its features. In addition junit-dataprovider is enabled to return multiple dataprovider methods.
/**
* {@link DataProviderMethodResolver} which returns all dataproviders which start with the name of the {@code testMethod}.
*/
private static class DataProviderStartWithTestMethodNameResolver extends DefaultDataProviderMethodResolver {
@Override
protected List<FrameworkMethod> findDataProviderMethods(List<TestClass> locations, String testMethodName, String useDataProviderValue) {
List<FrameworkMethod> result = new ArrayList<FrameworkMethod>();
for (TestClass location : locations) {
List<FrameworkMethod> dataProviderMethods = location.getAnnotatedMethods(DataProvider.class);
for (FrameworkMethod dataProviderMethod : dataProviderMethods) {
if (dataProviderMethod.getName().startsWith(testMethodName)) {
result.add(dataProviderMethod);
}
}
}
return result;
}
}
private static AtomicInteger counter;
@BeforeClass
public static void setupClass() {
counter = new AtomicInteger(0);
}
@AfterClass
public static void tearDownClass() {
assertThat(counter.get()).isEqualTo(6);
}
@DataProvider
public static Object[][] testNumberOne() {
// @formatter:off
return new Object[][] {
{ (byte) 1 },
};
// @formatter:on
}
@DataProvider
public static Object[][] testNumberTwo() {
// @formatter:off
return new Object[][] {
{ 2 },
{ Integer.valueOf(3) }
};
// @formatter:on
}
@DataProvider
public static Set<Number> testNumberThree() {
Set<Number> result = new LinkedHashSet<Number>();
result.add(4);
result.add(5L);
result.add(6.0);
return result;
}
@Test
@UseDataProvider(resolver = DataProviderStartWithTestMethodNameResolver.class)
public void testNumber(Number number) {
// When:
int count = counter.incrementAndGet();
// Then:
assertThat(count).isEqualTo(number.intValue());
}
For a full code example, see DataProviderResolverAcceptanceTest.java. Please also note that this is not the best test case as it depends on the order of the found dataprovider methods. But it works as a good enough demonstration, producing the following test result:
<testcase name="testNumber[0: 1]" classname="com.tngtech.java.junit.dataprovider.ResolverTest" time="0.145"/>
<testcase name="testNumber[0: 2]" classname="com.tngtech.java.junit.dataprovider.ResolverTest" time="0.0"/>
<testcase name="testNumber[1: 3]" classname="com.tngtech.java.junit.dataprovider.ResolverTest" time="0.0"/>
<testcase name="testNumber[0: 4]" classname="com.tngtech.java.junit.dataprovider.ResolverTest" time="0.001"/>
<testcase name="testNumber[1: 5]" classname="com.tngtech.java.junit.dataprovider.ResolverTest" time="0.0"/>
<testcase name="testNumber[2: 6.0]" classname="com.tngtech.java.junit.dataprovider.ResolverTest" time="0.0"/>
Please note that currently the numbering is reset for every dataprovider method, i.e. it starts three times from zero with three dataproviders. If this causes problems for you, please do not hesitate to open an issue here.
Since: v1.5.0
This feature is especially helpful if you will reuse a @DataProvider
for multiple tests of different classes.
@RunWith(DataProviderRunner.class)
public class DataProviderFromOtherLocationTest {
@Test
@UseDataProvider(value = "dataProviderIsStringLengthGreaterTwo",
location = StringDataProvider.class)
public void testIsStringLengthGreaterThanTwo(String str, boolean expected) {
// When:
boolean isGreaterThanTwo = (str == null) ? false : str.length() > 2;
// Then:
assertThat(isGreaterThanTwo).isEqualTo(expected);
}
}
import com.tngtech.java.junit.dataprovider.DataProvider;
public class StringDataProvider {
@DataProvider
public static Object[][] dataProviderIsStringLengthGreaterTwo() {
// @formatter:off
return new Object[][] {
{ "", false },
{ "1", false },
{ "12", false },
{ "123", true },
{ "Test", true },
};
// @formatter:on
}
}
Since: v1.10.0
@DataProvider
public static Object[][] dataProviderVarargs3() {
// @formatter:off
return $$(
$('a'),
$('b', 0),
$('c', 1, 2, 3)
);
// @formatter:on
}
@Test
@UseDataProvider("dataProviderVarargs3")
public void testVarargs3(char c, int... is) {
assertNotNull(c);
for (int i : is) {
assertNotNull(i);
}
}
@Test
// @formatter:off
@DataProvider({
"",
"a",
"x, y, z",
})
// @formatter:on
public void testVarargs2(String... strings) {
for (String s : strings) {
assertNotNull(s);
}
}
Note: For JUnit5 dataproviders this works out-of-the-box as expected since v2.0 using @BeforeAll
annotation. This only affects JUnit4 dataprovider implementation.
!!!Breaking change!!! if you use the results of a @BeforeClass method within a dataprovider method in v1.10.4 removing the @BeforeClass
support again, as there were various complains, see #49 and #64.
All static @BeforeClass
setup methods are executed before any @DataProvider
such that all static fields can be prepared in these test setup methods and smoothly accessed within @DataProvider
methods:
private static String emptyString = null;
private static String notEmptyString = null;
@BeforeClass
public static void setup() {
emptyString = "";
notEmptyString = "notEmpty";
}
@DataProvider
public static Object[][] dataProviderNotNullStringsSetInBeforeClass() {
// @formatter:off
return new Object[][] {
{ emptyString },
{ notEmptyString },
};
// @formatter:on
}
@Test
@UseDataProvider("dataProviderNotNullStringsSetInBeforeClass")
public void testNotNullStringsSetInBeforeClass(String str) {
// Given:
// Expected:
assertThat(str != null).isTrue();
}
Note:
@ClassRule
are not executed before the static @DataProvider
method currently because I see no possibility doing this. The problem is that JUnit rules are undividable "befores" and "afters" which internally surround a Statement
executing all created tests (besides some other things). To create all tests, though, the dataprovider methods must be executed already ... :-(
If you want to customize the test method names because they are too long or should fit a special need for later parsing, you can do this easily by customizing @DataProvider
s formatter()
. By default DataProviderPlaceholderFormatter
is used. This falls back on the origin mechansim via @DataProvider
s format()
. The following placeholders are provided by default (also see com.tngtech.java.junit.dataprovider.internal.placeholder:
Placeholder | Example | Description |
---|---|---|
%c |
DataProviderRunnerTest | Simple name of test method class (= Class#getSimpleName()) |
%cc |
com.tngtech.java .junit.dataprovider .DataProviderRunnerTest | Canonical name of test method class (= Class#getCanonicalName()) |
%m |
testIsEmptyString | Simple name of test method (= Method#getName()) |
%cm |
com.tngtech.test .java.junit.dataprovider .DataProviderJavaAcceptanceTest .testIsEmptyString(java.lang.String) | Complete signature of test method (= Method#toString()) |
%i |
13 | Index of the dataprovider test of current test method (starting at 0 }). Useful to generate unique method descriptions. |
%a[x] |
test, , 4 | Subscripting all arguments by positive or negative index (e.g. 1 ) and range (0..-2 ). All indices may either be positive (starting at 0 and increment) to number arguments from the beginning or negative (starting from -1 and decrement) to number arguments from the end. |
%na[x] |
arg0=test, arg1=, arg2=4 | Subscripting all named arguments as a[x] does but prefixes arguments with parameter names. |
%p[x] |
test, , 4 | Same as %a[x] . |
But be aware of using this feature, as it may break the following other features:
- Running all tests for one dataprovider (in various IDEs) and jumping to a test method by double-clicking it (in Eclipse) does only work if the custom
@DataProvider#format()
starts with the test method name (=%m
) followed by a character which is not a valid java identifier, e.g." "
,"["
,"("
,":"
, or"-"
. - If test method names are not unique within its class, it can cause indeterministic behavior!
// ...
static class PlusTestNameFormatter implements DataProviderTestNameFormatter {
@Override
public String format(Method testMethod, int invocationIndex, List<Object> arguments) {
return String.format("%s: %2d + %2d = %2d", testMethod.getName(), arguments.get(0), arguments.get(1),
arguments.get(2));
}
}
@DataProvider(formatter = PlusTestNameFormatter.class)
static Object[][] dataProviderPlus() {
// @formatter:off
return new Object[][] {
{ 0, 0, 0 },
{ -1, 0, -1 },
{ 0, 1, 1 },
{ 1, 1, 2 },
{ 1, -1, 0 },
{ -1, -1, -2 },
};
// @formatter:on
}
@Test
@UseDataProvider
void testPlus(int a, int b, int expected) {
// Expect:
assertThat(a + b).isEqualTo(expected);
}
@DataProvider(format = "%m: %p[0] * %p[1] == %p[2]")
public static Object[][] dataProviderMultiply() {
// @formatter:off
return new Object[][] {
{ 0, 0, 0 },
{ 0, 1, 0 },
{ 1, 1, 1 },
{ 1, -1, -1 },
{ -1, -1, 1 },
{ 1, 2, 2 },
{ 6, 7, 42 },
};
// @formatter:on
}
@Test
@UseDataProvider("dataProviderMultiply")
public void testMultiply(int a, int b, int expected) {
// Expect:
assertThat(a * b).isEqualTo(expected);
}
// ...
The results would look like:
<testcase name="testMultiply: 0 * 0 == 0" classname="com.tngtech.java.junit.dataprovider.TestNameFormatterTest" time="0.058"/>
<testcase name="testMultiply: -1 * 0 == 0" classname="com.tngtech.java.junit.dataprovider.TestNameFormatterTest" time="0.0"/>
<testcase name="testMultiply: 0 * 1 == 0" classname="com.tngtech.java.junit.dataprovider.TestNameFormatterTest" time="0.0"/>
<testcase name="testMultiply: 1 * 1 == 1" classname="com.tngtech.java.junit.dataprovider.TestNameFormatterTest" time="0.0"/>
<testcase name="testMultiply: 1 * -1 == -1" classname="com.tngtech.java.junit.dataprovider.TestNameFormatterTest" time="0.001"/>
<testcase name="testMultiply: -1 * -1 == 1" classname="com.tngtech.java.junit.dataprovider.TestNameFormatterTest" time="0.0"/>
<testcase name="testMultiply: 1 * 2 == 2" classname="com.tngtech.java.junit.dataprovider.TestNameFormatterTest" time="0.0"/>
<testcase name="testMultiply: -1 * 2 == -2" classname="com.tngtech.java.junit.dataprovider.TestNameFormatterTest" time="0.0"/>
<testcase name="testMultiply: -1 * -2 == 2" classname="com.tngtech.java.junit.dataprovider.TestNameFormatterTest" time="0.0"/>
<testcase name="testMultiply: -1 * -2 == 2" classname="com.tngtech.java.junit.dataprovider.TestNameFormatterTest" time="0.0"/>
<testcase name="testMultiply: 6 * 7 == 42" classname="com.tngtech.java.junit.dataprovider.TestNameFormatterTest" time="0.001"/>
For more information about the default placeholders, see DataProvider.java. If you want to further customize the test method name, you can implement and add your own placeholder as following:
public class StripParameterLengthPlaceholder extends ParameterPlaceholder {
private final int maxLength;
public StripParameterLengthPlaceholder(int maxLength) {
this.maxLength = maxLength;
}
@Override
protected String formatAll(Object[] parameters) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < parameters.length; i++) {
String formattedParameter = format(parameters[i]);
if (formattedParameter.length() > maxLength) {
stringBuilder.append(formattedParameter.substring(0, maxLength - 5));
stringBuilder.append("...");
stringBuilder.append(formattedParameter.substring(formattedParameter.length() - 5));
} else {
stringBuilder.append(formattedParameter);
}
if (i < parameters.length - 1) {
stringBuilder.append(", ");
}
}
return stringBuilder.toString();
}
}
// Note: is only called before test initialization in Runner's constructor if at least one "external"
// dataprovider (= static method) exists
static {
Placeholders.all().add(0, new StripParameterLengthPlaceholder(10));
}
@DataProvider
public static String[] dataProviderEqualsIgnoreCase() {
// @formatter:off
return new String[] {
"veryVeryLongMethodNameWhichMustBeStripped, null, false",
"veryVeryLongMethodNameWhichMustBeStripped, , false",
"veryVeryLongMethodNameWhichMustBeStripped, veryVeryLongMethodNameWhichMustBeStripped, true",
"veryverylongmethodnamewhichmustbestripped, veryVeryLongMethodNameWhichMustBeStripped, true",
"veryVeryLongMethodNameWhichMustBeStripped, veryverylongmethodnamewhichmustbestripped, true",
};
// @formatter:on
}
@Test
@UseDataProvider
public void testEqualsIgnoreCase(String methodName1, String methodName2, boolean expected) {
// Expected:
assertThat(methodName1.equalsIgnoreCase(methodName2)).isEqualTo(expected);
}
For the full example, see CustomPlaceholderAcceptanceTest.java.
Since: v1.8.0
The cache
option on @DataProvider
was introduced with v2.2. Before that the default was equivalent to cache = true
such that the reuse of dynamic dataproviders was not optimal.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExternalFile {
public enum Format {
CSV,
XML,
XLS;
}
Format format();
String value();
}
@DataProvider(cache = false)
public static Object[][] loadFromExternalFile(FrameworkMethod testMethod) {
String testDataFile = testMethod.getAnnotation(ExternalFile.class).value();
// Load the data from the external file here ...
return new Object[][] { { testDataFile } };
}
@Test
@UseDataProvider("loadFromExternalFile")
@ExternalFile(format = ExternalFile.Format.CSV, value = "testdata.csv")
public void testThatUsesUniversalDataProvider(String testData) {
// Expect:
assertThat(testData).isEqualTo("testdata.csv");
}
Thanks to @barancev for the pull request (#28) for parameters to dataproviders and to @weiro-9-w7 for addressing the caching problems (#105).
Since: v1.9.0
To be able to use the full power of these utility methods, add com.tngtech.java.junit.dataprovider.DataProviders.*
as [Eclipse][] type favorite (via Preferences -> Java -> Editor -> Content Assist -> Favorites
and New Type...
.
import static com.tngtech.java.junit.dataprovider.DataProviders.*;
@DataProvider
public static Object[][] dataProviderAdd() {
// @formatter:off
return $$(
$( -1, -1, -2 ),
$( -1, 0, -1 ),
$( 0, -1, -1 ),
$( 0, 0, 0 ),
$( 0, 1, 1 ),
$( 1, 0, 1 ),
$( 1, 1, 2 )
);
// @formatter:on
}
@DataProvider
public static Object[][] dataProviderStringIsNullOrEmpty() {
return testForEach(null, "");
}
@DataProvider
public static Object[][] dataProviderRoundingMode() {
return testForEach(java.math.RoundingMode.class);
}
Inspired by @michaeladler.
Since: v1.10.4
If @UseDataProvider
does not provide an explicitly given value()
the dataprovider method name is tried to be determined automatically by the following conventions in order:
-
@DataProvider
annotated method which name equals the test method name -
@DataProvider
annotated method whereby prefix is replaced one out of the following table:
Prefix | Replacement |
---|---|
test | dataProvider |
test | data |
-
@DataProvider
annotated method whereby additional prefixdataProvider
ordata
is given. Also the first letter of the original test method name is uppercased, e.g.shouldReturnTwoForOnePlusOne
could correspond todataProviderShouldReturnTwoForOnePlusOne
.
You can just add a @JvmStatic
annotation to the companion object function containing the dataprovider data and it plays nicely :-)
Here is a complete example:
import com.tngtech.java.junit.dataprovider.DataProvider
import com.tngtech.java.junit.dataprovider.DataProviderRunner
import com.tngtech.java.junit.dataprovider.DataProviders.`$$`
import com.tngtech.java.junit.dataprovider.DataProviders.`$`
import com.tngtech.java.junit.dataprovider.UseDataProvider
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(DataProviderRunner::class)
class DataTest {
companion object {
@DataProvider
@JvmStatic
fun testRelativeAngleProvider(): Array<Array<Any>> = `$$`(
// @formatter:off
`$`( 0, 0, 0),
`$`( 0, 1, 1),
`$`( 1, 0, 1),
`$`( 1, 1, 2),
`$`( 0, -1, -1),
`$`(-1, 0, -1),
`$`(-1, -1, -2),
`$`( 1, -1, 0),
`$`(-1, 2, 1)
// @formatter:on
)
}
@Test
@UseDataProvider(value = "testRelativeAngleProvider")
fun testRelativeAngles(a: Int, b: Int, c: Int) {
assert(a + b == c);
}
}
Since: v1.10.1
- Home
- Motivation, Distinction and FAQs
- Getting started
- Version compatibility
- Migration guides
-
Features
- Array syntax
- String syntax
- Iterable syntax
- Custom dataprovider method resolvers
- Change
@DataProvider
location - Varargs support
@BeforeClass
support (JUnit4 only)- Customize test method name
- Access
FrameworkMethod
in@DP
- Utility methods
- Convention over configuration
- Kotlin support
- OSGi compatible
MANIFEST.MF
- Tips and Tricks
- Release Notes
- Eclipse Template