简体   繁体   中英

Overwrite autowired fields by Mock object in spring web context

We have Spring web layer with controllers and service layer with services having autowired beans/services. We are trying to write integration test case for services by mocking them through web layer. In test case, we have created WebAppContext and deployed it on jetty server. In my test case, I am trying to get the context from server and replacing the service to be mocked by mock object by using reflection. But the problem is as all are LAZILY autowired, my mock gets overridden when actual autowired object gets initialized.

We need solution to replace the actual initialized object by mock object in the context while running test case.

When I am getting bean from context using getBean("beanName"),all autowired fields in the bean are null, any reason why and I have removed the 'default-lazy-init' from application context as well to avoid lazy loading.

see below code,I have depositService & withdrawService in AccountService. When I get 'Accountservice' from getBean(), it returns both these autowired varibles as null ie depositService=null & withdrawService = null.

@service
public class AccountServiceImpl implements AccountService{

@autowired
private Depositservice depositService;

@autowired
private WithdrawService withdrawService;
}

What you are looking for is implemented by the Springockito project.

You easily declare beans as mocks or spys using either XML or annotations.

I suggest however that you try to make your tests regular unit tests if possible since you are going to use mocks anyway.

I usually employ some test Spring context overrides through specific files named the same thing in my test classpath, which take over for normal beans in the main classpath during testing. Then obviously I use the Spring Junit Runner and other context annotations to bring in the starter files I want for my contexts.

Finally I found the answer.The problem is when spring is initializing the autowired property, it creates a proxy object around it. So whenever we have to set the mock object to any property we should be setting it in proxy object.

  1. get the web context.
  2. get the bean from the context where mock needs to be injected
  3. create mock object (I have used Mockito here to generate it)
  4. set the property using reflection utils.
  5. While setting the property ,unwrap the propxy object and then set its property.

Below is the code Snippet:

WebApplicationContext webContext = getWebContextBean();
StaticApplicationContext context = new StaticApplicationContext(webContext);
MockService mockObject = mock(DepositService.class );
AccountServiceImpl service = context.getBean( AccountServiceImpl.class );
ReflectionTestUtils.setField( unwrapProxy(service), "depositService", mockObject );
context.refresh();

UnwrapProxy will have following logic:

if ( AopUtils.isAopProxy( bean ) && bean instanceof Advised ) {
        Advised advised = (Advised)bean;
        bean = advised.getTargetSource().getTarget();
    }
return bean;

Get the context from server where you have deployed your app

WebApplicationContext getWebContextBean() {
    WebAppContext jettyWebAppContext = (WebAppContext)server.getHandler();
    ServletContext servletContext = jettyWebAppContext.getServletHandler().getServletContext();
    WebApplicationContext springWebAppContext = WebApplicationContextUtils.getWebApplicationContext( servletContext );
    return springWebAppContext;
}

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