Test Spring beans with different constructor args over JUnit using #ContextConfiguration - java

Description of the problem:
I would like users to configure spring beans with custom config files over spring XML configs, like this:
Note that only Strings should be configured by the user, all other beans should be #Autowired without the user knowing it!
<bean class="com.my.group.Provider">
<constructor-arg value="config1.proprietary"/>
<constructor-arg value="config2.proprietary"/>
</bean>
The Provider object looks (simplified) as follows:
public class Provider {
#Autowired
private Foo foo;
private final String[] configNames;
public Provider(final String... configs) {
this.configNames = Preconditions.checkNotNull(configs, "Provided configs must not be null!");
}
public List<Configs> getConfigs() {
return new foo.create(configNames); // here is more logic that I would actually like to test... (not just methods called on foo)
}
}
My question is:
How can I test this solution with various different string inputs, so that all tests can go into one JUnit Test class? Btw: I would like to avoid reflections...
(The unit tests below show what I mean. And they are already capable to do what I want, but they use reflections.)
What I did so far
is using reflections to change the field content afterwards, but tbh that is not sexy at all:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {ProviderTest.MyContext.class})
public class ProviderTest {
#Autowired
private Provider sut;
#Test
public void provide_oneConfig() throws NoSuchFieldException, IllegalAccessException {
setConfigFilesViaReflection(sut, "config1.proprietary"");
// When
List<Config> configs = sut.getConfigs();
// Then
assertEquals(1, configs.size());
}
#Test
public void provide_twoConfigs() throws NoSuchFieldException, IllegalAccessException {
setConfigFilesViaReflection(sut, "config1.proprietary", config2.proprietary");
// When
List<Config> configs = sut.getConfigs();
// Then
assertEquals(2, configs.size());
}
private void setConfigFilesViaReflection(final Provider sut, final String... configs) throws NoSuchFieldException,
IllegalAccessException {
Field configNamesField = Provider.class.getDeclaredField("configNames");
configNamesField.setAccessible(true);
configNamesField.set(sut, configs);
}
#Configuration
public static class MyContext {
#Bean
Provider provider() {
return new Provider("willBeOverridenByReflection");
}
#Bean
Foo foo() {
return new Foo(); // this one got mocked in my test
}
}

Sometimes asking a questions helps to search harder.
The #Qualifier / #Resource annotation make it possible to create several beans, and choose them per test like that:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {ProviderTest.MyContext.class})
public class ProviderTest {
#Autowired
#Qualifier("bar") // could also be #Resource (without #Autowired)
private Provider sut;
#Resource(name="baz")
private Provider sut2; // could also be #Qualifier(with #Autowired)
#Test
public void provide_oneConfig() throws NoSuchFieldException, IllegalAccessException {
// When
List<Config> configs = sut.getConfigs();
// Then
assertEquals(1, configs.size());
}
#Test
public void provide_twoConfigs() throws NoSuchFieldException, IllegalAccessException {
// When
List<Config> configs = sut2.getConfigs();
// Then
assertEquals(2, configs.size());
}
#Configuration
public static class MyContext {
#Bean("bar")
Provider providerBar() {
return new Provider"config1.proprietary");
}
#Bean("baz")
Provider providerBaz() {
return new Provider("config1.proprietary", "config2.proprietary");
}
#Bean
Foo foo() {
return new Foo(); // this one got mocked in my test
}
}
Found my answer here: Autowiring two different beans of same class

Related

Mocking of component with InjectMocks is not working for my test class

I have a spring boot app with autowired components. It works fine operationally, but mocking is not initializing the components properly. Here are the main components:
base processor:
#Component
public class Processor {
public String getType() { return null; }
public void transformInput(JsonObject data) { }
public void buildOutputRequest(String syncType) { }
}
, one of the 4 subtypes:
#Component
public class ProcessorType1 extends Processor {
#Override
public String getType() { return Type.TYPE1.getValue();}
public void transformInput(JsonObject data) {
// do dtuff
}
}
, supporting enum:
public enum Type {
TYPE1("TYPE1"),TYPE2("TYPE2"), TYPE3("TYPE3"), TYPE4("TYPE4");
private final String value;
public static final Map<Type, String> enumMap = new EnumMap<Type, String>(
Type.class);
static {
for (Type e : Type.values())
enumMap.put(e, e.getValue());
}
Type(String value) { this.value = value;}
public String getValue() { return value; }
}
,and the factory class:
#Component
public class ProcessorFactory {
#Autowired
public ProcessorFactory(List<Processor> processors) {
for (Processor processor : processors) {
processorCache.put(processor.getType(), processor);
}
}
private static final Map<String, Processor> processorCache = new HashMap<String, Processor>();
public static Processor getProcessor(String type) {
Processor service = processorCache.get(type);
if(service == null) throw new RuntimeException("Unknown type: " + type);
return service;
}
}
, then operationally, a calling service uses the factory similar to this:
#Service
MyService {
public processData (
// do stuff to get processor type and data
Processor processor = ProcessorFactory.getProcessor(type);
processor.transformInput(data);
)
}
Again, operationally this works fine. However, I attempt to mock the factory and its initialization like the following:
#RunWith(SpringJUnit4ClassRunner.class)
public class ProcessorFacTest
{
#InjectMocks
ProcessorFactory factory;
#Test
void testGetSyncProcessorDocument() {
String type = Type.TYPE1.getValue();
Processor processor = ProcessorFactory.getProcessor(type);
Assert.assertTrue(processor instanceof ProcessorType1);
}
}
My expectation was that since I am using #InjectMocks, and since ProcessorFactory has its constructor autowired, the constructor would be called by InjectMocks as part of the initialization. However, this is not happening. The processorCache is zero-length because the constructor is never called.
I realize I am mixing injection with static usages, but since it worked operationally, and since my understanding was that InjectMocks would handle the creation of the processorCache, that it should have worked for the test class as well, and its not.
I would be grateful for any ideas as to what I am doing wrong. Thank you
You never define any mocks that could be injected. Which dependencies should be autowired if you don't define any? The constructor is still called, but with an empty list of dependencies (use your debugger to set a breakpoint there and check for yourself).
It's also critical to note that mocks will return null, empty lists or 0/false by default for all methods, unless the mock has been set up properly.
You must define the mocks so that they can be picked up by #InjectMocks plus use the correct JUnit runner/extension:
#ExtendWith(MockitoExtension.class) // JUnit 5
// #RunWith(MockitoJUnitRunner.class) // JUnit 4
public class ProcessorFacTest
{
#Mock
ProcessorType1 processor1;
#Mock
ProcessorType2 processor2;
// ...
#InjectMocks
ProcessorFactory factory;
#BeforeEach // JUnit 5
// #Before // JUnit 4
void setup() {
Mockito.when(processor1.getType()).thenReturn(Type.TYPE1);
Mockito.when(processor2.getType()).thenReturn(Type.TYPE2);
}
#Test
void testGetSyncProcessorDocument() {
String type = Type.TYPE1.getValue();
Processor processor = ProcessorFactory.getProcessor(type);
Assert.assertTrue(processor instanceof ProcessorType1);
}
}
EDIT: the above won't work because the processors are not a direct dependency for your class under test, but are elements of a list. Mockito will not be able to inject the correct mocks.
And here's how you would write the test as a Spring test with mock beans:
#RunWith(SpringJUnit4ClassRunner.class)
public class ProcessorFacTest
{
#MockBean
ProcessorType1 processor1;
#MockBean
ProcessorType2 processor2;
// ...
#Autowired
ProcessorFactory factory;
#BeforeEach // JUnit 5
// #Before // JUnit 4
void setup() {
Mockito.when(processor1.getType()).thenReturn(Type.TYPE1.getValue());
Mockito.when(processor2.getType()).thenReturn(Type.TYPE2.getValue());
}
#Test
void testGetSyncProcessorDocument() {
String type = Type.TYPE1.getValue();
Processor processor = ProcessorFactory.getProcessor(type);
Assert.assertTrue(processor instanceof ProcessorType1);
}
}
But actually you don't need to use any annotations here, you could wire the dependencies manually just as simple:
public class ProcessorFacTest
{
ProcessorFactory factory;
#BeforeEach // JUnit 5
// #Before // JUnit 4
void setup() {
final ProcessorType1 processor1 = Mockito.mock(ProcessorType1.class);
final ProcessorType1 processor2 = Mockito.mock(ProcessorType2.class);
Mockito.when(processor1.getType()).thenReturn(Type.TYPE1);
Mockito.when(processor2.getType()).thenReturn(Type.TYPE2);
factory = new ProcessorFactory(
List.of(
processor1,
processor2,
// ...
));
}
#Test
void testGetSyncProcessorDocument() {
String type = Type.TYPE1.getValue();
Processor processor = ProcessorFactory.getProcessor(type);
Assert.assertTrue(processor instanceof ProcessorType1);
}
}
If your processors are simply, easy to instantiate and don't depend on other classes, it might even be simpler (and better, YMMV) to simply use the real collaborators instead of mocks.
And it might be easier to create a test implementation of your processor type, which can be easier to set up than a mock object created dynamically with Mockito. The code would look like this:
#BeforeEach // JUnit 5
// #Before // JUnit 4
void setup() {
factory = new ProcessorFactory(
List.of(
new TestProcessor(Type.TYPE1),
new TestProcessor(Type.TYPE2),
// ...
));
}
private static class TestProcessor extends Processor {
private final Type type;
public TestProcessor(final Type type) { this.type = type; }
public String getType() { return type.getValue(); }
// Base class methods do nothing already. If they were, you would override them here with an empty implementation:
#Override
public void transformInput(JsonObject data) { /* do nothing */ }
#Override
public void buildOutputRequest(String syncType) { /* do nothing */ }
}
NB. It's bad practice to use names that are already defined in the JDK. Type is one such name (java.lang.reflect.Type).
It might also be worthwhile to read Why is my class not calling my mocked methods in unit test? to get a good overview of common gotchas when setting up mocks.

Retryable annotation - Junit5 - Mockito - is it possible

Is it possible to write unit test using Junit 5 mockito for retryable annotations?
I am having a service interface which has only one method, which downloads the file from remote url
#service
interface downloadpdf{
#Retryable(value = { FileNotFoundException.class, HttpClientErrorException.class }, maxAttempts = 5, backoff = #Backoff(delay = 1000))
public string downloadpdffile(string remoteurl, string pdfname);
}
I have tried referring sites and found using Spring4JunitRunner implementation to test retry. Got confused with implementation. Is it possible to write unit test using Junit 5 mockito for retryable annotations?. Could you please elaborate on the solution here?
You need to use #SpringJUnitConfig (which is the equivalent of the JUnit4 runner). Or #SpringBootTest as you are using Boot.
#Retryable only works with beans managed by Spring - it wraps the bean in a proxy.
#SpringBootApplication
#EnableRetry
public class So71849077Application {
public static void main(String[] args) {
SpringApplication.run(So71849077Application.class, args);
}
}
#Component
class RetryableClass {
private SomeService service;
void setService(SomeService service) {
this.service = service;
}
#Retryable
void retryableMethod(String in) {
service.callme();
throw new RuntimeException();
}
#Recover
void recover(Exception ex, String in) {
service.failed();
}
}
interface SomeService {
void callme();
void failed();
}
#SpringBootTest
class So71849077ApplicationTests {
#MockBean
SomeService service;
#Test
void testRetry(#Autowired RetryableClass retryable) {
SomeService service = mock(SomeService.class);
retryable.setService(service);
retryable.retryableMethod("foo");
verify(service, times(3)).callme();
verify(service).failed();
}
}
I was also trying to implement this using Junit5.
Tried various options but that didn't help. Then after googling for few hours, got the following link and it helped to succeed.
https://doctorjw.wordpress.com/2022/04/29/spring-testing-a-single-bean-in-junit-5-springextension/
Reference code below, for detailed explanation, please refer the blog.
#Component
public class MyClass {
private ObjectMapper objectMapper;
private RestTemplate restTemplate;
#Value("${testValue:5}")
private int value;
#Retryable(....)
public void doStuff() throws SomeException {
...
}
}
What I’ve discovered is, if I declare my test class this way:
#ExtendWith( SpringExtension.class )
#Import( { MyClass.class, ObjectMapper.class } )
#EnableRetry
public class MyClassTest {
#Autowired
private MyClass myClass;
#MockBean
private RestTemplate restTemplate;
#Autowired
private ObjectMapper objectMapper;
#BeforeEach
public void setup() {
// If we are going to jack with the object configuration,
// we need to do so on the actual object, not the Spring proxy.
// So, use AopTestUtils to get around the proxy to the actual obj.
TestingUtils.setFieldValue( AopTestUtils.getTargetObject( myClass ), "value", 10 );
}
}
You will notice the inclusion of 1 other class, TestingUtils.class. This class looks like:
public class TestingUtils {
public static void setFieldValue( Object object, String fieldName, Object value ) {
Field field = ReflectionUtils.findField( object.getClass(), fieldName );
ReflectionUtils.makeAccessible( field );
ReflectionUtils.setField( field, object, value );
}
}
All credits goes to the author of the blog.

Spring bean scope for "one object per test method"

I have a test utility for with I need to have a fresh instance per test method (to prevent that state leaks between tests). So far, I was using the scope "prototype", but now I want to be able to wire the utility into another test utility, and the wired instances shall be the same per test.
This appears to be a standard problem, so I was wondering if there is a "test method" scope or something similar?
This is the structure of the test class and test utilities:
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyTest {
#Autowired
private TestDriver driver;
#Autowired
private TestStateProvider state;
// ... state
// ... methods
}
#Component
#Scope("prototype") // not right because MyTest and TestStateProvider get separate instances
public class TestDriver {
// ...
}
#Component
public class TestStateProvider {
#Autowired
private TestDriver driver;
// ...
}
I'm aware that I could use #Scope("singleton") and #DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) but this refreshes more than I need – a new TestDriver instance for each test would be enough. Also, this approach is error-prone because all tests using the TestDriver would need to know that they also need the #DirtiesContext annotation. So I'm looking for a better solution.
It is actually pretty easy to implement a testMethod scope:
public class TestMethodScope implements Scope {
public static final String NAME = "testMethod";
private Map<String, Object> scopedObjects = new HashMap<>();
private Map<String, Runnable> destructionCallbacks = new HashMap<>();
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if (!scopedObjects.containsKey(name)) {
scopedObjects.put(name, objectFactory.getObject());
}
return scopedObjects.get(name);
}
#Override
public void registerDestructionCallback(String name, Runnable callback) {
destructionCallbacks.put(name, callback);
}
#Override
public Object remove(String name) {
throw new UnsupportedOperationException();
}
#Override
public String getConversationId() {
return null;
}
#Override
public Object resolveContextualObject(String key) {
return null;
}
public static class TestExecutionListener implements org.springframework.test.context.TestExecutionListener {
#Override
public void afterTestMethod(TestContext testContext) throws Exception {
ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) testContext
.getApplicationContext();
TestMethodScope scope = (TestMethodScope) applicationContext.getBeanFactory().getRegisteredScope(NAME);
scope.destructionCallbacks.values().forEach(callback -> callback.run());
scope.destructionCallbacks.clear();
scope.scopedObjects.clear();
}
}
#Component
public static class ScopeRegistration implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
factory.registerScope(NAME, new TestMethodScope());
}
}
}
Just register the test execution listener, and there will be one instance per test of all #Scope("testMethod") annotated types:
#RunWith(SpringRunner.class)
#SpringBootTest
#TestExecutionListeners(listeners = TestMethodScope.TestExecutionListener.class,
mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
public class MyTest {
#Autowired
// ... types annotated with #Scope("testMethod")
}
I ran into the same problem some time ago and came to this solution:
Use Mocks
I wrote some methods to create specific mockito settings to add behavior to each mock.
So create a TestConfiguration class with following methods and bean definition.
private MockSettings createResetAfterMockSettings() {
return MockReset.withSettings(MockReset.AFTER);
}
private <T> T mockClass(Class<T> classToMock) {
return mock(classToMock, createResetAfterMockSettings());
}
and your bean definition will look like:
#Bean
public TestDriver testDriver() {
return mockClass(TestDriver .class);
}
MockReset.AFTER is used to reset the mock after the test method is run.
And finally add a TestExecutionListeners to your Test class:
#TestExecutionListeners({ResetMocksTestExecutionListener.class})

NPE on spring autowires form TestExecutionListener

This might have been coded wrongly, but any idea how it should be done is appreciated.
I have this class TestClass which needs to inject many service class. Since I can't use #BeforeClass on #Autowired objects, I result on using AbstractTestExecutionListener. Everything was working as expected but when I'm on #Test blocks, all objects are evaluated null.
Any idea how to solve this?
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { ProjectConfig.class })
#TestExecutionListeners({ TestClass.class })
public class TestClass extends AbstractTestExecutionListener {
#Autowired private FirstService firstService;
// ... other services
// objects needs to initialise on beforeTestClass and afterTestClass
private First first;
// ...
// objects needs to be initialised on beforeTestMethod and afterTestMethod
private Third third;
// ...
#Override public void beforeTestClass(TestContext testContext) throws Exception {
testContext.getApplicationContext().getAutowireCapableBeanFactory().autowireBean(this);
first = firstService.setUp();
}
#Override public void beforeTestMethod(TestContext testContext) throws Exception {
third = thirdService.setup();
}
#Test public void testOne() {
first = someLogicHelper.recompute(first);
// ...
}
// other tests
#Override public void afterTestMethod(TestContext testContext) throws Exception {
thirdService.tearDown(third);
}
#Override public void afterTestClass(TestContext testContext) throws Exception {
firstService.tearDown(first);
}
}
#Service
public class FirstService {
// logic
}
For starters, having your test class implement AbstractTestExecutionListener is not a good idea. A TestExecutionListener should be implemented in a stand-alone class. So you might want to rethink that approach.
In any case, your current configuration is broken: you disabled all default TestExecutionListener implementations.
To include the defaults, try the following configuration instead.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ProjectConfig.class)
#TestExecutionListeners(listeners = TestClass.class, mergeMode = MERGE_WITH_DEFAULTS)
public class TestClass extends AbstractTestExecutionListener {
// ...
}
Regards,
Sam (author of the Spring TestContext Framework)

How can I use the Parameterized JUnit test runner with a field that's injected using Spring?

I'm using Spring to inject the path to a directory into my unit tests. Inside this directory are a number of files that should be used to generate test data for parameterized test cases using the Parameterized test runner. Unfortunately, the test runner requires that the method that provides the parameters be static. This doesn't work for my situation because the directory can only be injected into a non-static field. Any ideas how I can get around this?
You can use a TestContextManager from Spring. In this example, I'm using Theories instead of Parameterized.
#RunWith(Theories.class)
#ContextConfiguration(locations = "classpath:/spring-context.xml")
public class SeleniumCase {
#DataPoints
public static WebDriver[] drivers() {
return new WebDriver[] { firefoxDriver, internetExplorerDriver };
}
private TestContextManager testContextManager;
#Autowired
SomethingDao dao;
private static FirefoxDriver firefoxDriver = new FirefoxDriver();
private static InternetExplorerDriver internetExplorerDriver = new InternetExplorerDriver();
#AfterClass
public static void tearDown() {
firefoxDriver.close();
internetExplorerDriver.close();
}
#Before
public void setUpStringContext() throws Exception {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
}
#Theory
public void testWork(WebDriver driver) {
assertNotNull(driver);
assertNotNull(dao);
}
}
I found this solution here : How to do Parameterized/Theories tests with Spring
I assume you are using JUnit 4.X since you mentioned the Parameterized test runner. This implies you aren't using #RunWith(SpringJUnit4ClassRunner). Not a problem, just listing my assumptions.
The following uses Spring to get the test files directory from the XML file. It doesn't inject it, but the data is still available to your test. And in a static method no less.
The only disadvantage I see is that it may mean your Spring config is getting parsed/configured multiple times. You could load just a smaller file with test specific info if need be.
#RunWith(Parameterized.class)
public class MyTest {
#Parameters
public static Collection<Object[]> data() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("/jeanne/jeanne.xml");
String dir = ctx.getBean("testFilesDirectory", String.class);
// write java code to link files in test directory to the array
return Arrays.asList(new Object[][] { { 1 } });
}
// rest of test class
}
For someone reading this late 2015 or later, Spring 4.2 has, in addition to SpringJUnit4ClassRunner added SpringClassRule and SpringMethodRule which leverage the support for Spring TestContext Framework.
This means first class support for any Runner like MockitoJUnitRunner or Parameterized:
#RunWith(Parameterized.class)
public class FibonacciTest {
#ClassRule public static final SpringClassRule SCR = new SpringClassRule();
#Rule public final SpringMethodRule springMethodRule = new SpringMethodRule();
long input;
long output;
public FibonacciTest(long input, long output) { this.input = input; ...}
#Test
public void testFibonacci() {
Assert.assertEquals(output, fibonacci(input));
}
public List<Long[]> params() {
return Arrays.asList(new Long[][] { {0, 0}, {1, 1} });
}
}
It's enough to annotate test class with #RunWith(Parameterized.class) and #ContextConfiguration, use #Autowired for dependency injection and use TestContextManager in constructor for initialization, e.g.:
#RunWith(Parameterized.class)
#ContextConfiguration(classes = TestConfig.class)
public class MyTest {
#Autowired
private DataSource dataSource;
private final int param;
#Parameterized.Parameters
public static List<Object[]> params() {
return Arrays.asList(new Object[][]{
{1},
{2},
});
}
public MyTest(int p) {
this.param = p;
new TestContextManager(getClass()).prepareTestInstance(this);
}
#Test
public void testSomething() {
…
}
}
Here is a first solution without JUnit 4.12 parameterized factory, below an improved solution with it.
Static context without transactional support
Let Spring do all configuration parsing and autowiring with TestContextManager class.
The trick is to use a fake test instance to get autowired fields and pass them to the parameterized test which will effectively run.
But keep in mind prepareTestInstance() do the autowiring but doesn't manage test transaction and other nice stuffs handled by beforeTestMethod() and afterTestMethod().
#RunWith(Parameterized.class)
#ContextConfiguration(locations = {"/test-context.xml", "/mvc-context.xml"})
#WebAppConfiguration
#ActiveProfiles("test-profile")
public class MyTest {
#Parameters
public static Collection<Object[]> params() throws Exception {
final MyTest fakeInstance = new MyTest();
final TestContextManager contextManager = new TestContextManager(MyTest.class);
contextManager.prepareTestInstance(fakeInstance);
final WebApplicationContext context = fakeInstance.context;
// Do what you need with Spring context, you can even access web resources
final Resource[] files = context.getResources("path/files");
final List<Object[]> params = new ArrayList<>();
for (Resource file : files) {
params.add(new Object[] {file, context});
}
return params;
}
#Parameter
public Resource file;
#Autowired
#Parameter(1)
public WebApplicationContext context;
}
However a drawback appear if you have a lot of autowired fields because you have to manually pass them to the array parameters.
Parameterized factory with full Spring support
JUnit 4.12 introduce ParametersRunnerFactory which allow to combine parameterized test and Spring injection.
public class SpringParametersRunnerFactory implements ParametersRunnerFactory {
#Override
public Runner createRunnerForTestWithParameters(TestWithParameters test) throws InitializationError {
final BlockJUnit4ClassRunnerWithParameters runnerWithParameters = new BlockJUnit4ClassRunnerWithParameters(test);
return new SpringJUnit4ClassRunner(test.getTestClass().getJavaClass()) {
#Override
protected Object createTest() throws Exception {
final Object testInstance = runnerWithParameters.createTest();
getTestContextManager().prepareTestInstance(testInstance);
return testInstance;
}
};
}
}
The factory can be added to previous test class to give full Spring support like test transaction, reinit dirty context and servlet test. And of course there no more need to pass autowired fields from fake test instance to parameterized test.
#UseParametersRunnerFactory(SpringParametersRunnerFactory.class)
#RunWith(Parameterized.class)
#ContextConfiguration(locations = {"/test-context.xml", "/mvc-context.xml"})
#WebAppConfiguration
#Transactional
#TransactionConfiguration
public class MyTransactionalTest {
#Parameters
public static Collection<Object[]> params() throws Exception {
final MyTransactionalTest fakeInstance = new MyTransactionalTest();
final TestContextManager contextManager = new TestContextManager(MyTransactionalTest.class);
contextManager.prepareTestInstance(fakeInstance);
final WebApplicationContext context = fakeInstance.context;
// Do what you need with Spring context, you can even access web resources
final Resource[] files = context.getResources("path/files");
final List<Object[]> params = new ArrayList<>();
for (Resource file : files) {
params.add(new Object[] {file});
}
return params;
}
#Parameter
public Resource file;
#Autowired
private WebApplicationContext context;
}
I use the following solution with the Parameterized.class without any problem:
http://bmocanu.ro/coding/320/combining-junit-theoriesparameterized-tests-with-spring/
#ContextConfiguration(value = "classpath:test-context.xml")
public abstract class AbstractJunitTest extends AbstractJUnit4SpringContextTests {
private static TestContextManager testContextManager = null;
private static DAOFactory daoFactory = null;
#Before
public void initApplicationContext() throws Exception {
if (testContextManager == null) {
testContextManager = new TestContextManager(getClass());
testContextManager.prepareTestInstance(this);
daoFactory = (DAOFactory)applicationContext.getBean("daoFactory");
}
}
protected DAOFactory getDaoFactory() throws Exception {
return daoFactory;
}
}
#RunWith(Parameterized.class)
public class SomeTestClass extends AbstractJunitTest {
...
}
Remember that Spring inject using #Autowired, but also with setter. So instead of using #Autowired, use the setter:
private static String directory;
public void setDirectory(String directory) {
this.directory = directory;
}
public static String getDirectory() {
return directory;
}

Categories

Resources