简体   繁体   English

在Spring Web上下文中通过Mock对象覆盖自动装配的字段

[英]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. 我们有带有控制器的Spring Web层和带有自动装配bean /服务的服务的服务层。 We are trying to write integration test case for services by mocking them through web layer. 我们试图通过在Web层上对服务进行模拟来编写服务的集成测试用例。 In test case, we have created WebAppContext and deployed it on jetty server. 在测试案例中,我们创建了WebAppContext并将其部署在码头服务器上。 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. 当我使用getBean(“ beanName”)从上下文中获取bean时,bean中的所有自动装配字段都为null,无论出于何种原因,我也从应用程序上下文中删除了“ default-lazy-init”,以避免延迟加载。

see below code,I have depositService & withdrawService in AccountService. 见下面的代码,我在AccountService中有depositService和withdrawService。 When I get 'Accountservice' from getBean(), it returns both these autowired varibles as null ie depositService=null & withdrawService = null. 当我从getBean()获得'Accountservice'时,它会将这两个自动连接的变量都返回为null,即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. 您要查找的内容由Springockito项目实现。

You easily declare beans as mocks or spys using either XML or annotations. 您可以使用XML或注释轻松地将bean声明为模拟或间谍。

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. 我通常在测试类路径中通过名称相同的特定文件使用一些测试Spring上下文覆盖,这些文件在测试期间接管主类路径中的普通bean。 Then obviously I use the Spring Junit Runner and other context annotations to bring in the starter files I want for my contexts. 然后显然我使用了Spring Junit Runner和其他上下文注释来引入我想要的上下文启动文件。

Finally I found the answer.The problem is when spring is initializing the autowired property, it creates a proxy object around it. 最后我找到了答案。问题是当spring初始化autowired属性时,它围绕它创建了一个代理对象。 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 从需要注入模拟的上下文中获取bean
  3. create mock object (I have used Mockito here to generate it) 创建模拟对象(我在这里使用了Mockito来生成它)
  4. set the property using reflection utils. 使用反射工具设置属性。
  5. While setting the property ,unwrap the propxy object and then set its property. 设置属性时,请解开propxy对象,然后设置其属性。

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: UnwrapProxy将具有以下逻辑:

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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