-
Notifications
You must be signed in to change notification settings - Fork 164
Features
Below you can find code examples for all supported features. You can find most of the code examples below and a lot further in
- DataProviderJavaAcceptanceTest.java and StringDataProvider.java, as well as
- DataProviderGroovyAcceptanceTest.groovy.
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:off
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).
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
}
}
Please note that if you only have a single parameter test method, since v1.10.3 you can also use List<Object>
instead.
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);
}
}
!!!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 ... :-(
Since: v1.9.0
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 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. |
%p[x] |
test, , 4 | Subscripting all parameters 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 parameters from the beginning or negative (starting from -1 and decrement) to number parameters from the end. |
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!
// ...
@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 result in [...]/TEST-com.tngtech.test.java.junit.dataprovider.DataProviderJavaAcceptanceTest.xml
would look like:
<testcase name="testMultiply: 0 * 0 == 0" classname="com.tngtech.test.java.junit.dataprovider.DataProviderJavaAcceptanceTest" time="0.058"/>
<testcase name="testMultiply: -1 * 0 == 0" classname="com.tngtech.test.java.junit.dataprovider.DataProviderJavaAcceptanceTest" time="0.0"/>
<testcase name="testMultiply: 0 * 1 == 0" classname="com.tngtech.test.java.junit.dataprovider.DataProviderJavaAcceptanceTest" time="0.0"/>
<testcase name="testMultiply: 1 * 1 == 1" classname="com.tngtech.test.java.junit.dataprovider.DataProviderJavaAcceptanceTest" time="0.0"/>
<testcase name="testMultiply: 1 * -1 == -1" classname="com.tngtech.test.java.junit.dataprovider.DataProviderJavaAcceptanceTest" time="0.001"/>
<testcase name="testMultiply: -1 * -1 == 1" classname="com.tngtech.test.java.junit.dataprovider.DataProviderJavaAcceptanceTest" time="0.0"/>
<testcase name="testMultiply: 1 * 2 == 2" classname="com.tngtech.test.java.junit.dataprovider.DataProviderJavaAcceptanceTest" time="0.0"/>
<testcase name="testMultiply: -1 * 2 == -2" classname="com.tngtech.test.java.junit.dataprovider.DataProviderJavaAcceptanceTest" time="0.0"/>
<testcase name="testMultiply: -1 * -2 == 2" classname="com.tngtech.test.java.junit.dataprovider.DataProviderJavaAcceptanceTest" time="0.0"/>
<testcase name="testMultiply: -1 * -2 == 2" classname="com.tngtech.test.java.junit.dataprovider.DataProviderJavaAcceptanceTest" time="0.0"/>
<testcase name="testMultiply: 6 * 7 == 42" classname="com.tngtech.test.java.junit.dataprovider.DataProviderJavaAcceptanceTest" 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();
}
}
@BeforeClass
public static void setup() {
Placeholders.all().add(0, new StripParameterLengthPlaceholder(10));
}
@AfterClass
public static void teardown() {
Placeholders.reset();
}
@Test
// @formatter:off
@DataProvider({
"veryVeryLongMethodNameWhichMustBeStripped, null, false",
"veryVeryLongMethodNameWhichMustBeStripped, , false",
"veryVeryLongMethodNameWhichMustBeStripped, veryVeryLongMethodNameWhichMustBeStripped, true",
"veryverylongmethodnamewhichmustbestripped, veryVeryLongMethodNameWhichMustBeStripped, true",
"veryVeryLongMethodNameWhichMustBeStripped, veryverylongmethodnamewhichmustbestripped, true"
})
// @formatter:on
public void testEqualsIgnoreCase(String methodName1, String methodName2, boolean expected) {
// Expected:
assertThat(methodName1.equalsIgnoreCase(methodName2)).isEqualTo(expected);
}
For the full example, see CustomPlaceholderAcceptanceTest.java.
Note: If you want to globally add Placeholders.all().add(0, new StripParameterLengthPlaceholder(10));
, you can better do it within a static initializer in a test base class.
Since: v1.8.0
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExternalFile {
public enum Format {
CSV,
XML,
XLS;
}
Format format();
String value();
}
@DataProvider
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).
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
.
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