Overriding an Autowired Bean in Unit Tests

SpringSpring BootSpring Annotations

Spring Problem Overview


Is there a simple way I can easily override an autowired bean in specific unit tests? There is only a single bean of every type in the compile classes so it's not a problem for autowiring in this case. The test classes would contain additional mocks. When running a unit test I'd simply like to specify an additional Configuration that says basically, while running this unit test use this mock instead of the standard bean.

Profiles seem a bit overkill for what I require and I'm not sure this would be achievable with the Primary annotation as different unit test could have different mocks.

Spring Solutions


Solution 1 - Spring

If you just simply want to provide a different bean in your tests, i think you don't need to use spring profiles or mockito.

Just do the following:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { TestConfig.class })
public class MyTest
{
	@Configuration
	@Import(Application.class) // the actual configuration
	public static class TestConfig
	{
		@Bean
		public IMyService myService()
		{
			return new MockedMyService();
		}
	}
	
	@Test
	public void test()
	{
		....
	}
}

NOTE: tested with spring boot 1.3.2 / spring 4.2.4

Solution 2 - Spring

In Spring Boot 1.4 there's a simple way for doing that:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { MyApplication.class })
public class MyTests {
    @MockBean
    private MyBeanClass myTestBean;

    @Before
    public void setup() {
         ...
         when(myTestBean.doSomething()).thenReturn(someResult);
    }

    @Test
    public void test() {
         // MyBeanClass bean is replaced with myTestBean in the ApplicationContext here
    }
}

Solution 3 - Spring

I had similar problem and I solved with a mix and I find this one more useful and reusable. I created a spring profile for the tests and a config class that overrides the beans I want to mock in a very simple way:

@Profile("test")
@Configuration
@Import(ApplicationConfiguration.class)
public class ConfigurationTests {

    @MockBean
    private Producer kafkaProducer;

    @MockBean
    private SlackNotifier slackNotifier;

}

By doing that I can @Autowire those mock beans and use mockito to verify on them. Main advantage is that now all tests seamlessly get the mock beans without any per-test change. Tested with:

> spring boot 1.4.2

Solution 4 - Spring

You should use spring profiles in order to know what kind of bean you want to use in different contexts.

http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html

Solution 5 - Spring

Since Spring Boot 1.4.0 instead of explicitly specifying @Configuration for tests, simply add static nested class annotated with @TestConfiguration and provide your replacement @Bean annotated with @Primary.

@TestConfiguration will be added to your primary Spring Boot test context (which means your production bean will still be created), but the one from @TestConfiguration will be used, because of the @Primary.

Solution 6 - Spring

As mats.nowak commented, @ContextConfiguration is useful for this.

Say a parent test class is like:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/some-dao-stuff.xml"
    ,"classpath:spring/some-rest-stuff.xml"
    ,"classpath:spring/some-common-stuff.xml"
    ,"classpath:spring/some-aop-stuff.xml"
    ,"classpath:spring/some-logging-stuff.xml"
    ,"classpath:spring/some-services-etc.xml"
})
public class MyCompaniesBigTestSpringConfig {
...

Create a child test class:

package x.y.z;
@ContextConfiguration
public class MyOneOffTest extends MyCompaniesBigTestSpringConfig {
...

and put in src/test/resources/x/y/z/MyOneOffTest-context.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       					   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
						   http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.0.xsd">


    <bean id="widgetsService" class="com.mycompany.mydept.myservice.WidgetsService" primary="true" />

</beans>

That widgetsService bean will override (take the place of) the bean defined in the main config xml (or Java config). See about inheritLocations Also Note the default -context.xml file. Example of that here. Update: I had to add primary="true", apparently it's needed.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsamblakeView Question on Stackoverflow
Solution 1 - SpringteoView Answer on Stackoverflow
Solution 2 - SpringSergey ShcherbakovView Answer on Stackoverflow
Solution 3 - SpringIsrael FernándezView Answer on Stackoverflow
Solution 4 - SpringEddú MeléndezView Answer on Stackoverflow
Solution 5 - SpringKirillView Answer on Stackoverflow
Solution 6 - SpringawgtekView Answer on Stackoverflow