Skip to content

Commit

Permalink
introduce option on @dataProvider if its result should be cached (#105)
Browse files Browse the repository at this point in the history
  • Loading branch information
aaschmid committed Jan 29, 2018
1 parent 643eed6 commit 6eaaf46
Show file tree
Hide file tree
Showing 24 changed files with 482 additions and 133 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.tngtech.test.junit.dataprovider;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.concurrent.atomic.AtomicInteger;

import org.junit.jupiter.params.ParameterizedTest;

import com.tngtech.junit.dataprovider.DataProvider;
import com.tngtech.junit.dataprovider.UseDataProvider;

class CacheDataProviderResultsAcceptanceTest {

// works if test discovery order is equal to execution order
public static final AtomicInteger noOfTestsCallsUsingNotCachedDataProvider = new AtomicInteger(0);

private static final AtomicInteger noOfCachedDataProviderCalls = new AtomicInteger(0);
private static final AtomicInteger noOfNotCachedDataProviderCalls = new AtomicInteger(0);

@DataProvider
static Object[][] dataProviderCachedDataProviderResults() {
// @formatter:off
return new Object[][] {
{ noOfCachedDataProviderCalls.incrementAndGet() },
};
// @formatter:on
}

@ParameterizedTest
@UseDataProvider("dataProviderCachedDataProviderResults")
void testCachedDataProviderResultsOne(int noOfDataProvderCalls) {
// Expected:
assertThat(noOfDataProvderCalls).isEqualTo(1);
}

@ParameterizedTest
@UseDataProvider("dataProviderCachedDataProviderResults")
void testCachedDataProviderResultsTwo(int noOfDataProvderCalls) {
// Expected:
assertThat(noOfDataProvderCalls).isEqualTo(1);
}

@DataProvider(cache = false)
public static Object[][] dataProviderDoNotCacheDataProviderResults() {
// @formatter:off
return new Object[][] {
{ noOfNotCachedDataProviderCalls.incrementAndGet() },
};
// @formatter:on
}

@ParameterizedTest
@UseDataProvider("dataProviderDoNotCacheDataProviderResults")
public void testDoNotCacheDataProviderResultsOne(int noOfDataProvderCalls) {
// Expected:
assertThat(noOfDataProvderCalls).isEqualTo(noOfTestsCallsUsingNotCachedDataProvider.incrementAndGet());
}

@ParameterizedTest
@UseDataProvider("dataProviderDoNotCacheDataProviderResults")
public void testDoNotCacheCachedDataProviderResultsTwo(int noOfDataProvderCalls) {
// Expected:
assertThat(noOfDataProvderCalls).isEqualTo(noOfTestsCallsUsingNotCachedDataProvider.incrementAndGet());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.tngtech.test.junit.dataprovider;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.params.ParameterizedTest;

import com.tngtech.junit.dataprovider.UseDataProvider;

class CachedDataProviderResultsGloballyAcceptanceTest {

@ParameterizedTest
@UseDataProvider(value = "dataProviderCachedDataProviderResults", location = CacheDataProviderResultsAcceptanceTest.class)
void testCachedDataProviderResultsOne(int noOfDataProvderCalls) {
// Expected:
assertThat(noOfDataProvderCalls).isEqualTo(1);
}

@ParameterizedTest
@UseDataProvider(value = "dataProviderCachedDataProviderResults", location = CacheDataProviderResultsAcceptanceTest.class)
void testCachedDataProviderResultsTwo(int noOfDataProvderCalls) {
// Expected:
assertThat(noOfDataProvderCalls).isEqualTo(1);
}

@ParameterizedTest
@UseDataProvider(value = "dataProviderDoNotCacheDataProviderResults", location = CacheDataProviderResultsAcceptanceTest.class)
public void testDoNotCacheDataProviderResultsOne(int noOfDataProvderCalls) {
// Expected:
assertThat(noOfDataProvderCalls).isEqualTo(
CacheDataProviderResultsAcceptanceTest.noOfTestsCallsUsingNotCachedDataProvider.incrementAndGet());
}

@ParameterizedTest
@UseDataProvider(value = "dataProviderDoNotCacheDataProviderResults", location = CacheDataProviderResultsAcceptanceTest.class)
public void testDoNotCacheCachedDataProviderResultsTwo(int noOfDataProvderCalls) {
// Expected:
assertThat(noOfDataProvderCalls).isEqualTo(
CacheDataProviderResultsAcceptanceTest.noOfTestsCallsUsingNotCachedDataProvider.incrementAndGet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,9 @@ protected ConverterContext getConverterContext(DataProvider dataProvider) {
ReflectionSupport.newInstance(dataProvider.stringConverter()), dataProvider.splitBy(),
dataProvider.convertNulls(), dataProvider.trimValues(), dataProvider.ignoreEnumCase());
}

@Override
protected boolean cacheDataProviderResult(DataProvider dataProviderAnnotation) {
return dataProviderAnnotation.cache();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,9 @@ protected ConverterContext getConverterContext(DataProvider dataProvider) {
ReflectionSupport.newInstance(dataProvider.stringConverter()), dataProvider.splitBy(),
dataProvider.convertNulls(), dataProvider.trimValues(), dataProvider.ignoreEnumCase());
}

@Override
protected boolean cacheDataProviderResult(DataProvider dataProviderAnnotation) {
return dataProviderAnnotation.cache();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ public Stream<? extends Arguments> provideArguments(ExtensionContext context) th

DataProviderResolverContext resolverContext = getDataProviderResolverContext(context, sourceAnnotation);
return findDataProviderMethods(resolverContext).stream().flatMap(dpm -> {
Object data = invokeDataProviderMethodToRetrieveData(dpm, context);

DATAPROVIDER_ANNOTATION dataProviderAnnotation = dpm.getAnnotation(dataProviderAnnotationClass);
boolean cacheDataProviderResult = cacheDataProviderResult(dataProviderAnnotation);

Object data = invokeDataProviderMethodToRetrieveData(dpm, cacheDataProviderResult, context);
return convertData(testMethod, data, getConverterContext(dataProviderAnnotation));
});
}
Expand All @@ -81,6 +82,17 @@ protected abstract DataProviderResolverContext getDataProviderResolverContext(Ex
*/
protected abstract ConverterContext getConverterContext(DATAPROVIDER_ANNOTATION dataProvider);

/**
* @param dataProviderAnnotation on the test method which is providing the converter context; never {@code null}
* @return {@code true} if and only if dataprovider result should be cached or evaluated otherwise. Defaults to
* {@code true} for backwards compatibility reasons.
* @see DataProvider#cache()
*/
protected boolean cacheDataProviderResult(
@SuppressWarnings("unused") DATAPROVIDER_ANNOTATION dataProviderAnnotation) {
return true;
}

/**
* Retrieves the test data from given dataprovider method.
*
Expand All @@ -89,8 +101,29 @@ protected abstract DataProviderResolverContext getDataProviderResolverContext(Ex
*
* @return a list of methods, each method bound to a parameter combination returned by the dataprovider
* @throws NullPointerException if and only if one of the given arguments is {@code null}
*
* @deprecated available for backwards compatibility, use new
* {@link #invokeDataProviderMethodToRetrieveData(Method, boolean, ExtensionContext)} instead
* @see #invokeDataProviderMethodToRetrieveData(Method, boolean, ExtensionContext)
*/
@Deprecated
protected Object invokeDataProviderMethodToRetrieveData(Method dataProviderMethod, ExtensionContext context) {
return invokeDataProviderMethodToRetrieveData(dataProviderMethod, true, context);
}

/**
* Retrieves the test data from given dataprovider method.
*
* @param dataProviderMethod the dataprovider method that gives the parameters; never {@code null}
* @param cacheDataProviderResult determines if the dataprovider result should be cached using
* {@code dataProviderMethod} as key
* @param context the execution context to use to create a {@link TestInfo} if required; never {@code null}
*
* @return a list of methods, each method bound to a parameter combination returned by the dataprovider
* @throws NullPointerException if and only if one of the given arguments is {@code null}
*/
protected Object invokeDataProviderMethodToRetrieveData(Method dataProviderMethod, boolean cacheDataProviderResult,
ExtensionContext context) {
checkNotNull(dataProviderMethod, "'dataProviderMethod' must not be null");
checkNotNull(context, "'context' must not be null");

Expand All @@ -105,7 +138,9 @@ protected Object invokeDataProviderMethodToRetrieveData(Method dataProviderMetho
ExtensionRegistry extensionRegistry = createRegistryWithDefaultExtensions(emptyConfigurationParameters());
Object data = executableInvoker.invoke(dataProviderMethod, context.getTestInstance().orElse(null), context,
extensionRegistry);
store.put(dataProviderMethod, data);
if (cacheDataProviderResult) {
store.put(dataProviderMethod, data);
}
return data;

} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@
*/
boolean ignoreEnumCase() default false;

/**
* @return {@code true} if and only if the result of this dataprovider should be cached. Otherwise it will be
* evaluated for every usage. This could be necessary if it contains dynamic results, e.g. depending on a
* provided parameter. Default is {@code true}.
*/
boolean cache() default true;

/**
* @return a custom converter converting {@link Object}{@code []} data to proper arguments
* @see ObjectArrayConverter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,9 @@ protected ConverterContext getConverterContext(DataProvider dataProvider) {
ReflectionSupport.newInstance(dataProvider.stringConverter()), dataProvider.splitBy(),
dataProvider.convertNulls(), dataProvider.trimValues(), dataProvider.ignoreEnumCase());
}

@Override
protected boolean cacheDataProviderResult(DataProvider dataProviderAnnotation) {
return dataProviderAnnotation.cache();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ protected DataProviderResolverContext getDataProviderResolverContext(ExtensionCo
protected ConverterContext getConverterContext(Annotation dataProvider) {
return converterContext;
}

@Override
protected boolean cacheDataProviderResult(Annotation dataProviderAnnotation) {
return true;
}
};

MockitoAnnotations.initMocks(this);
Expand All @@ -81,7 +86,7 @@ void testInvokeDataProviderMethodToRetrieveDataShouldThrowParameterResolutionExc

// When:
Exception result = assertThrows(ParameterResolutionException.class,
() -> underTest.invokeDataProviderMethodToRetrieveData(dataProviderMethod, extensionContext));
() -> underTest.invokeDataProviderMethodToRetrieveData(dataProviderMethod, true, extensionContext));

// Then:
assertThat(result).hasMessageMatching("Exception while invoking dataprovider method '.*': .*");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.tngtech.test.junit.dataprovider;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.concurrent.atomic.AtomicInteger;

import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith;

import com.tngtech.junit.dataprovider.DataProvider;
import com.tngtech.junit.dataprovider.UseDataProvider;
import com.tngtech.junit.dataprovider.UseDataProviderExtension;

@ExtendWith(UseDataProviderExtension.class)
class CacheDataProviderResultsAcceptanceTest {

// works if test discovery order is equal to execution order
public static final AtomicInteger noOfTestsCallsUsingNotCachedDataProvider = new AtomicInteger(0);

private static final AtomicInteger noOfCachedDataProviderCalls = new AtomicInteger(0);
private static final AtomicInteger noOfNotCachedDataProviderCalls = new AtomicInteger(0);

@DataProvider
static Object[][] dataProviderCachedDataProviderResults() {
// @formatter:off
return new Object[][] {
{ noOfCachedDataProviderCalls.incrementAndGet() },
};
// @formatter:on
}

@TestTemplate
@UseDataProvider("dataProviderCachedDataProviderResults")
void testCachedDataProviderResultsOne(int noOfDataProvderCalls) {
// Expected:
assertThat(noOfDataProvderCalls).isEqualTo(1);
}

@TestTemplate
@UseDataProvider("dataProviderCachedDataProviderResults")
void testCachedDataProviderResultsTwo(int noOfDataProvderCalls) {
// Expected:
assertThat(noOfDataProvderCalls).isEqualTo(1);
}

@DataProvider(cache = false)
public static Object[][] dataProviderDoNotCacheDataProviderResults() {
// @formatter:off
return new Object[][] {
{ noOfNotCachedDataProviderCalls.incrementAndGet() },
};
// @formatter:on
}

@TestTemplate
@UseDataProvider("dataProviderDoNotCacheDataProviderResults")
public void testDoNotCacheDataProviderResultsOne(int noOfDataProvderCalls) {
// Expected:
assertThat(noOfDataProvderCalls).isEqualTo(noOfTestsCallsUsingNotCachedDataProvider.incrementAndGet());
}

@TestTemplate
@UseDataProvider("dataProviderDoNotCacheDataProviderResults")
public void testDoNotCacheCachedDataProviderResultsTwo(int noOfDataProvderCalls) {
// Expected:
assertThat(noOfDataProvderCalls).isEqualTo(noOfTestsCallsUsingNotCachedDataProvider.incrementAndGet());
}
}
Loading

0 comments on commit 6eaaf46

Please sign in to comment.