简体   繁体   中英

Spring / Mock components that are retrieved by using the context directly

We have a project that uses Spring annotations to configure its context. To test this project we are using Mockito and it's Spring extension.

In tests I need to override some beans with mock/spy version.

With the @Mock / @Spy and @InjectMock annotations I have been able to use spy for beans using autowiring mechanism.

Now I have a third party component which create another Spring context and then merge the 2 contexts together. This third party component retrieve beans using a call to the context:

applicationContext.getBean(key);

In this case, the @Mock/@Spy and @InjectMock combination is not working.

The 'workaround' solution I have put in place is an XML file in which I declare my spied bean:

<mockito:spy beanName="beanToSpy"/>

To stay in the annotation world, I have tried springockito-annotations as mentioned in these similar questions: Injecting Mockito mocks into a Spring bean and its duplicate: How to inject a Mock in a Spring Context

But the bean is not spied or mocked, I've probably a configuration error.

My current setup is:

A base class that is in charge of the Spring config for test:

@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("test")
@ContextConfiguration(loader= SpringockitoContextLoader.class, locations ={"/config.xml","/test-config.xml"})
public abstract class BaseTest {
  //...
}

A test class that would like to use a mocked bean:

public class MyTest extends BaseTest {
  @ReplaceWithMock @Autowired MyService myService;
  @WrapWithSpy @Autowired OtherService otherService;

  @Test public void someTest() { 
    doReturn(x).when(myService).call();
    doReturn(y).when(otherService).process();
  }
}

Unfortunately in MyTest , the beans are not replaced by their mock / spy versions, it is the plain old regular version.

EDIT: The third party component that does the lookup is using its own spring parent context and add the current spring context into its own. The lookup to retrieve the component that I want to be mocked occurs after the context has been fully loaded.

What should I do to properly replace the bean in the context with a mock / spy version ? What is wrong with the way I'm using @WrapWithSpy / @ReplaceWithMock ?

When does the call to

applicationContext.getBean(key);

happens? Is it possible that it retrieves the bean before the SpringockitoContextLoader has a chance to replace it with a spy?

One solution to stay in annotation world would be to override the bean in java config:

@Bean
public MyBeanType myBeanType() {
    return spy(new MyBeanType(...))
}

The more conventional way to perform this is by simply mocking them in the test as required :

public class MyTest extends BaseTest {
    @Test public void someTest() { 
        MyService myMockService = Mockito.mock(MyService.class);
        // define when's
       // perform verification
      }

You can inject using SpringReflectionTestUtils, or if using setter injection just set normally.

If you use a global mocked bean in a test class with multiple tests, the results can get confusing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM