2

I have webApplication based on SpringMVC and all beans are difined through annotations. Today I try to write test for my controllers. I put first one and tried to mock service which are used in this controllor. All this I did on the following way:

1) create context file for test clientControllerTest-context.xml

<import resource="classpath:spring-context.xml" />

<bean id="ConnectionDB" name="ConnectionDB" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="biz.podoliako.carwash.services.impl.ConnectDB" />
</bean>

where spring-context.xml is a main context file which are used in my webApplication (including information about real ConnectionDB bean)

2)create test class with following configuation

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:controllers/clientControllerTest-context.xml"})
@WebAppConfiguration

when the test was run, the NoUniqueBeanDefinitionException exeption was catched. I hoped that spring overwrite bean ConnectionDB but in fact it found 2 beans with one name and spring cannot chose which one has to be used.

Please, explaine me how can I use my main spring-context and mock one of the bean for testing and avoiding NoUniqueBeanDefinitionException if it possibe ofcause.

NB: I think createing context with all configuration for test is a bad idea therefore I try to use my main spring-context.

Bizon4ik
  • 2,604
  • 4
  • 20
  • 46

1 Answers1

5

You can define profiles for your Spring app, and tie your @Configuration classes or @Bean methods (or even your custom meta-annotations if you use any) to named profiles, even multiple profiles if you want. Then you could define profiles with names test, development, production or whatever custom scenario comes to your mind, and have your beans registered to your Spring context based on the currently active profile(s).

Define your beans for both the test and anotherTest profile like this:

@Configuration
@Profile({"test", "anotherTest"})
public class SomeConfig {...}

Or in an xml file:

...
<beans profile="test, anotherTest">
    <bean .../>
</beans>
...

Define your production restricted beans in a similar way to avoid conflict of beans in your profiles. Then, use the @ActiveProfiles annotation on your JUnit test class to indicate what profiles you want to be active while running the tests:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(...)
@ActiveProfiles({"test", "anotherTest"})

See this other question Default profile in Spring 3.1 on how to activate a profile by default in a webapp or the javadoc for org.springframework.core.env.Environment if you want to do it programatically.

Community
  • 1
  • 1
Nándor Előd Fekete
  • 6,988
  • 1
  • 22
  • 47
  • I changed my clientControllerTest-context.xml (mock bean was wrapped up by and add in my test the following annotation: @ActiveProfiles(profiles = {"test"}). But it's not sovle the problem, I see the same exeption. May be it's happend beause I didn't define default profile? But how to set up profile for beans which are defined through annotation? – Bizon4ik Jan 17 '16 at 23:30
  • You have defined your test context bean to be active only when the "test" profile is active, then activate the "test" profile for your JUnit test. But you still have your "real ConnectionDB bean" in your application context, which, I guess you didn't restrict to a profile yet. So you get two beans with the same interface or name and Spring can't decide which one to use in autowiring. You need to restrict your "real ConnectionDB bean" to another profile (`production` maybe?) and have that profile active in your web application context as in the question linked in my last paragraph. – Nándor Előd Fekete Jan 17 '16 at 23:38