Spring JUnit: How to Mock autowired component in autowired component
I've got a Spring component I'd like to test and this component has an autowired attribute which I need to change for the purpose of unit testing. The problem is, that the class uses the autowired component inside the post-construct method so I'm not able to replace it(i.e. via ReflectionTestUtils) before it's actually used.
How should I do that?
This is the class I want to test:
@Component
public final class TestedClass{
@Autowired
private Resource resource;
@PostConstruct
private void init(){
//I need this to return different result
resource.getSomething();
}
}
And this is the base of a test case:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= "classpath:applicationContext.xml")
public class TestedClassTest{
@Autowired
private TestedClass instance;
@Before
private void setUp(){
//this doesn't work because it's executed after the bean is instantiated
ReflectionTestUtils.setField(instance, "resource", new Resource("something"));
}
}
Is there some way to replace the resource with something else before the postconstruct method is invoked? Like to tell Spring JUnit runner to autowire different instance?
You could use Mockito. I am not sure with PostConstruct
specifically, but this generally works:
// Create a mock of Resource to change its behaviour for testing
@Mock
private Resource resource;
// Testing instance, mocked `resource` should be injected here
@InjectMocks
@Resource
private TestedClass testedClass;
@Before
public void setUp() throws Exception {
// Initialize mocks created above
MockitoAnnotations.initMocks(this);
// Change behaviour of `resource`
when(resource.getSomething()).thenReturn("Foo");
}
Spring Boot 1.4 introduced testing annotation called @MockBean
. So now mocking and spying on Spring beans is natively supported by Spring Boot.
You can provide a new testContext.xml in which the @Autowired
bean you define is of the type you need for your test.
I created blog post on the topic. It contains also link to Github repository with working example.
The trick is using test configuration, where you override original spring bean with fake one. You can use @Primary
and @Profile
annotations for this trick.