A TestNG-like dataprovider runner for JUnit having a simplified syntax compared to all the existing JUnit features.
—
This document covers the core components needed to use JUnit DataProvider: the custom runner and the two primary annotations.
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.DataProviderFilter;
import com.tngtech.java.junit.dataprovider.DataProviderFrameworkMethod;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import org.junit.runner.manipulation.Filter;
import org.junit.runner.manipulation.NoTestsRemainException;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;The DataProviderRunner is a custom JUnit runner that extends BlockJUnit4ClassRunner to enable TestNG-style data provider functionality.
public class DataProviderRunner extends BlockJUnit4ClassRunner {
/**
* Creates a DataProviderRunner to run supplied test class.
* @param clazz the test Class to run
* @throws InitializationError if the test Class is malformed
*/
public DataProviderRunner(Class<?> clazz) throws InitializationError
/**
* Apply custom filter that supports data provider row filtering.
* @param filter the Filter to be wrapped or applied
* @throws NoTestsRemainException if no tests remain after filtering
*/
public void filter(Filter filter) throws NoTestsRemainException
/**
* Initialize helper classes for data conversion, test generation, and validation.
* Override this method to customize internal behavior.
*/
protected void initializeHelpers()
/**
* Generate exploded list of test methods including parameterized variants.
* @return list of all test methods including data provider expansions
*/
protected List<FrameworkMethod> computeTestMethods()
// Protected fields for customization
protected DataConverter dataConverter;
protected TestGenerator testGenerator;
protected TestValidator testValidator;
}@RunWith(DataProviderRunner.class)
public class MyTest {
// Test methods with data providers
}The runner automatically:
The @DataProvider annotation marks methods as data providers or provides data directly inline.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataProvider {
/**
* Define list of parameters as regex-separated Strings for the test method.
* @return list of regex-separated String parameters
*/
String[] value() default {};
/**
* Delimiting regex for splitting String data. Defaults to comma.
* @return the regex to split String data
*/
String splitBy() default COMMA;
/**
* Convert "null" strings to null values. Default is true.
* @return true if "null" strings should be converted to null
*/
boolean convertNulls() default true;
/**
* Trim leading/trailing whitespace from split strings. Default is true.
* @return true if string data should be trimmed
*/
boolean trimValues() default true;
/**
* Format pattern for generating test method descriptions.
* Available placeholders: %c, %cc, %m, %cm, %i, %p[x]
* @return the format pattern for test method names
*/
String format() default DEFAULT_FORMAT;
/**
* Ignore case when converting enum values. Default is false.
* @return true if enum conversion should be case-insensitive
*/
boolean ignoreEnumCase() default false;
// Constants
String COMMA = ",";
String NULL = "null";
String DEFAULT_FORMAT = "%m[%i: %p[0..-1]]";
}// Method-based data provider
@DataProvider
public static Object[][] testData() {
return new Object[][] {
{ "input1", "expected1" },
{ "input2", "expected2" }
};
}
// Inline string data provider
@Test
@DataProvider({"test,4", "hello,5", "world,5"})
public void testStringLength(String input, int expectedLength) {
assertEquals(expectedLength, input.length());
}
// Custom configuration
@DataProvider(
splitBy = "\\|", // Use pipe as delimiter
convertNulls = false, // Keep "null" as string
trimValues = false, // Preserve whitespace
format = "%m[%i]" // Simple index format
)
public static String[] customData() {
return new String[] { "a|1", "b|2", "null|0" };
}Object[][] - Standard two-dimensional arrayIterable<Iterable<?>> - Nested iterablesIterable<?> - Single iterable (each element becomes one test case)String[] - Array of regex-separated parameter stringsThe @UseDataProvider annotation connects test methods to their data providers.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface UseDataProvider {
enum ResolveStrategy {
/** Use first matching resolver */
UNTIL_FIRST_MATCH,
/** Aggregate all matching resolvers */
AGGREGATE_ALL_MATCHES
}
/**
* Name or pattern to derive the data provider method.
* Default uses convention-based naming.
* @return value from which data provider method can be derived
*/
String value() default DEFAULT_VALUE;
/**
* Classes where data provider methods should be searched.
* Default searches in the test class itself.
* @return array of Classes to search for data provider methods
*/
Class<?>[] location() default {};
/**
* Resolvers used to find data provider methods.
* @return resolver classes to use for data provider method resolution
*/
Class<? extends DataProviderMethodResolver>[] resolver()
default { DefaultDataProviderMethodResolver.class };
/**
* Strategy for resolving multiple data provider methods.
* @return strategy for handling multiple resolver matches
*/
ResolveStrategy resolveStrategy() default ResolveStrategy.UNTIL_FIRST_MATCH;
// Constants
String DEFAULT_VALUE = "<use_convention>";
}// Convention-based (data provider method has same name as test method)
@Test
@UseDataProvider
public void testStringLength(String input, int expected) { /* ... */ }
@DataProvider
public static Object[][] testStringLength() { /* ... */ }
// Explicit data provider name
@Test
@UseDataProvider("stringData")
public void testStringLength(String input, int expected) { /* ... */ }
// Data provider in external class
@Test
@UseDataProvider(value = "commonTestData", location = TestDataClass.class)
public void testWithExternalData(String input, int expected) { /* ... */ }
// Multiple resolvers with aggregation
@Test
@UseDataProvider(
resolver = { CustomResolver1.class, CustomResolver2.class },
resolveStrategy = ResolveStrategy.AGGREGATE_ALL_MATCHES
)
public void testWithMultipleResolvers(Object data) { /* ... */ }When using @UseDataProvider without specifying a value, the DefaultDataProviderMethodResolver tries these naming patterns in order:
testMethod() → testMethod()testMethod() → dataProviderMethod() or dataMethod()testMethod() → dataProviderTestMethod() or dataTestMethod()Internal class that represents parameterized test methods generated by the data provider.
public class DataProviderFrameworkMethod extends FrameworkMethod {
/**
* Create a parameterized test method.
* @param method the original test method
* @param idx index of the data provider row
* @param parameters parameters for this test invocation
* @param nameFormat format pattern for generating test name
*/
public DataProviderFrameworkMethod(Method method, int idx,
Object[] parameters, String nameFormat)
/**
* Get formatted name for this parameterized test.
* @return formatted test method name
*/
public String getName()
/**
* Invoke test method with data provider parameters.
* @param target test instance
* @param params ignored - uses data provider parameters instead
* @return test method result
*/
public Object invokeExplosively(Object target, Object... params) throws Throwable
// Package-private fields for testing
final int idx;
final Object[] parameters;
final String nameFormat;
}This class is primarily used internally by the DataProviderRunner but may be relevant for custom test runners or advanced integrations.
A specialized filter for parameterized tests that allows filtering specific data provider rows.
public class DataProviderFilter extends Filter {
/**
* Create a filter that can handle data provider test filtering.
* @param filter the original filter to wrap
*/
public DataProviderFilter(Filter filter)
/**
* Determine if a test should run based on data provider row matching.
* @param description test method description
* @return true if the test should run
*/
public boolean shouldRun(Description description)
/**
* Get description of the wrapped filter.
* @return filter description
*/
public String describe()
// Pattern for parsing data provider test descriptions
static final Pattern DESCRIPTION_PATTERN;
static final Pattern GENEROUS_DESCRIPTION_PATTERN;
}The DataProviderFilter is automatically used by DataProviderRunner to enable filtering of individual parameterized test cases:
// When running specific parameterized test cases, the filter can target:
// - Specific test method: MyTest.testMethod
// - Specific data provider row: MyTest.testMethod[2: param1, param2]
// - All rows of a method: MyTest.testMethod[*]
@RunWith(DataProviderRunner.class)
public class FilterableTest {
@Test
@UseDataProvider("testData")
public void testMethod(String input, int expected) {
assertEquals(expected, input.length());
}
@DataProvider
public static Object[][] testData() {
return new Object[][] {
{"hello", 5}, // Row 0
{"world", 5}, // Row 1
{"test", 4} // Row 2
};
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-tngtech-java--junit-dataprovider