Skip to content

Features

Andreas Schmid edited this page Aug 11, 2015 · 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);
    }
}

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

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

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

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

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.

OSGi compatible MANIFEST.MF

Since: v1.10.1