Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding an Autowired Bean in Unit Tests

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.

like image 406
samblake Avatar asked Feb 19 '15 12:02

samblake


People also ask

How do you override a spring bean?

Bean Overriding Spring beans are identified by their names within an ApplicationContext. Thus, bean overriding is a default behavior that happens when we define a bean within an ApplicationContext which has the same name as another bean. It works by simply replacing the former bean in case of a name conflict.

Can you Autowire byType when more than?

if there is exactly one bean of the property type in the container. If there is more than one, a fatal exception is thrown, and this indicates that you may not use byType autowiring for that bean. If there are no matching beans, nothing happens; the property is not set.

How do you exclude a bean from being available for Autowiring?

If you are using Spring XML configuration then you can exclude a bean from autowiring by setting the autowire-candidate attribute of the <bean/> element to false. That way container makes that specific bean definition unavailable to the autowiring infrastructure.

Can you Autowire in a jUnit?

Also note that we can wire other spring beans in our jUnit test classes using @Autowired annotation.


Video Answer


3 Answers

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

like image 61
teo Avatar answered Oct 19 '22 08:10

teo


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
    }
}
like image 52
Sergey Shcherbakov Avatar answered Oct 19 '22 08:10

Sergey Shcherbakov


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

like image 7
Israel Fernández Avatar answered Oct 19 '22 06:10

Israel Fernández