Skip to content

Features

Andreas Schmid edited this page Oct 21, 2016 · 50 revisions

Below you can find code examples for all supported features. You can find most of the code examples below and a lot further in

Array syntax

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.

String syntax

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 Strings (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,
  • Strings, and
  • types having single-argument String constructor are supported. The String "null" will be passed as null object or "null" String according to #convertNulls() (default true).
    // @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.

List syntax

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. Also Object is no longer necessary as element type. You can use anything, e.g. bounded and wildcard type parameters.

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
    }
}

Custom dataprovider method resolvers

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 compatible with any version. See sections Change @DataProvider location and Convention over configuration.

TBD

Change @DataProvider location

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
    }
}

Varargs support

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);
        }
    }

@BeforeClass support

Since: v1.9.2 Until: v1.10.3

!!!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 ... :-(

Customize test method name

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 @DataProviders 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.

Access FrameworkMethod in @DataProvider

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).

Utility methods

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.

Convention over configuration

Dataprovider method name

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 prefix dataProvider or data is given. Also the first letter of the original test method name is uppercased, e.g. shouldReturnTwoForOnePlusOne could correspond to dataProviderShouldReturnTwoForOnePlusOne.

OSGi compatible MANIFEST.MF

Since: v1.10.1