This repository contains TestNG DataProvider wrapper which helps to supply test data in a more flexible way.
Common DataProvider forces using quite old and ugly syntax which expects one of the following types to be returned from DP method's body:
- Object[][]
- Iterator<Object[]>
That's weird, as developers tend to use Stream and Collection API for data manipulation in the modern Java world.
Just imaging if you could use the following syntax to supply some filtered and sorted data into test method's signature:
@DataSupplier
public Stream<User> getData() {
return Stream.of(
new User("Petya", "password2"),
new User("Virus Petya", "password3"),
new User("Mark", "password1"))
.filter(u -> !u.getName().contains("Virus"))
.sorted(comparing(User::getPassword));
}
@Test(dataProvider = "getData")
public void shouldSupplyStreamData(final User user) {
// ...
}
Much better and flexible than two-dimensional arrays or iterators, isn't it?
And what if we don't want to iterate the same test N times depending on collection size? What if we want to extract its values and inject into test's signature like the following?
@DataSupplier(transpose = true)
public List<User> getExtractedData() {
return StreamEx.of(
new User("username1", "password1"),
new User("username2", "password2"))
.toList();
}
@Test(dataProvider = "getExtractedData")
public void shouldSupplyExtractedListData(final User... users) {
// ...
}
You can do even more, if you want to perform a Java-like flatMap operation for each row:
@DataSupplier(flatMap = true)
public Map<Integer, String> getInternallyExtractedMapData() {
return EntryStream.of(asList("user3", "user4")).toMap();
}
@Test(dataProvider = "getInternallyExtractedMapData")
public void supplyInternallyExtractedMapData(final Integer key, final String value) {
// not implemented
}
- Collection
- Map
- Entry
- Object[]
- double[]
- int[]
- long[]
- Stream / StreamEx
- Tuple
- A single Object of any common or custom type
Add the following configuration into build.gradle:
repositories {
jcenter()
}
dependencies {
compile('org.testng:testng:6.13.1',
'io.github.sskorol:test-data-supplier:1.4.0'
)
}
test {
useTestNG() {
listeners << 'io.github.sskorol.core.DataProviderTransformer'
}
}
Check a separate project with usage examples.
Add the following configuration into pom.xml:
<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.13.1</version>
</dependency>
<dependency>
<groupId>io.github.sskorol</groupId>
<artifactId>test-data-supplier</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
<configuration>
<properties>
<property>
<name>listener</name>
<value>io.github.sskorol.core.DataProviderTransformer</value>
</property>
</properties>
</configuration>
</plugin>
</plugins>
</build>
Check a separate project with usage examples.
If you're going to run tests directly from IDE via TestNG run configuration, you have to explicitly set io.github.sskorol.core.DataProviderTransformer into Listeners section:
Otherwise, you'll get an exception about missing DataProvider, as test listeners' specified in Gradle / Maven settings
are ignored while using TestNG run configuration. And TestNG itself will try to locate methods with a common annotation,
instead of DataSupplier.
Instead of a common DataProvider annotation use the following:
@DataSupplier
public T getData() {
//...
}
DataSupplier supports the following args: name, transpose, flatMap, runInParallel and indices.
You can refer DataSupplier the same way as with TestNG DataProvider:
@Test(dataProvider = "getData")
public void supplyData(final T data) {
// ...
}
// or
@Test(dataProviderClass = ExternalDataProvider.class, dataProvider = "getData")
public void supplyExternalData(final T data) {
// ...
}
Check io.github.sskorol.testcases package for more examples.
In case of @DataSupplier
usage along with @Factory
annotation, it's required to explicitly provide dataProviderClass
arg.
Otherwise, you'll get an exception about missing DataProvider
. That's a limitation caused by TNG-1631.
@NoArgsConstructor
public class InternalFactoryTests {
@DataSupplier
public StreamEx getConstructorData() {
return IntStreamEx.rangeClosed(1, 3).boxed();
}
@DataSupplier
public String getTestData() {
return "data";
}
@Factory(dataProvider = "getConstructorData", dataProviderClass = InternalFactoryTests.class)
public InternalFactoryTests(final int index) {
// not implemented
}
@Test(dataProvider = "getTestData")
public void internalFactoryTest(final String data) {
// not implemented
}
}
DataSupplierInterceptor interface allows tracking original DataProvider method calls for accessing additional meta-data. You can use the following snippet for getting required info:
public class DataSupplierInterceptorImpl implements DataSupplierInterceptor {
private static final Map<ITestNGMethod, DataSupplierMetaData> META_DATA = new ConcurrentHashMap<>();
@Override
public void beforeDataPreparation(final ITestContext context, final ITestNGMethod method) {
}
@Override
public void afterDataPreparation(final ITestContext context, final ITestNGMethod method) {
}
@Override
public void onDataPreparation(final DataSupplierMetaData testMetaData) {
META_DATA.putIfAbsent(testMetaData.getTestMethod(), testMetaData);
}
@Override
public Collection<DataSupplierMetaData> getMetaData() {
return META_DATA.values();
}
}
This class should be then loaded via SPI mechanism. Just create META-INF/services folder in resources root, and add a new file io.github.sskorol.core.DataSupplierInterceptor with a full path to implementation class.
Test Data Supplier is integrated with IntelliJ IDEA in a form of plugin. Just install test-data-supplier-plugin from the official JetBrains repository.
More information about its features could be found on the related GitHub page.