5

好的,我们正在谈论 Spring (3.2.0) MVC

我们定义了一个切入点,以“围绕”注释触发,如下所示:

@Around("@annotation(MyAnnotation)")
public void someFunction() {

}

然后在控制器中我们有:

@Controller
@Component
@RequestMapping("/somepath")
public class MyController {

    @Autowired
    private MyService service;

    ...

    @MyAnnotation
    @RequestMapping(value = "/myendpoint", method = RequestMethod.POST, produces = "application/json")
    @ResponseBody
    public Object myEndpoint(@RequestBody MyRequestObject requestObject, HttpServletRequest request, HttpServletResponse response) {
        ...
        return service.doSomething(requestObject);
    }         
}

然后我们有一个如下所示的单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = {"../path/to/applicationContext.xml"})
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
public class MyControllerTest {

    private MockMvc mockMvc;

    @InjectMocks
    private MyController controller;

    @Mock
    private MyService myService;    

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
    }


    @Test
    public void myTest() {
        MyRequest request = new MyRequest();
        MyResponse response = new MyResponse();
        String expectedValue = "foobar";

        Mockito.when(myService.doSomething((MyRequest) Mockito.any())).thenReturn(response);

        MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.post("/myendpoint");

        String request = IOUtils.toString(context.getResource("classpath:/request.json").getURI());

        builder.content(request);
        builder.contentType(MediaType.APPLICATION_JSON);

        mockMvc.perform(builder)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.someKey").value(expectedValue));

        Mockito.verify(myService, Mockito.times(1)).doSomething((MyRequest) Mockito.any());
    }
}

测试运行良好,但围绕注释 (MyAnnotation) 定义的方面没有执行。当端点由真实请求触发时(例如在 servlet 容器中运行时),这执行得很好,但在测试中运行时不会触发。

这是 MockMvc 的一个特殊“功能”,它不会触发方面吗?

仅供参考,我们的 applicationContext.xml 配置为:

<aop:aspectj-autoproxy/>

正如我提到的,这些方面在现实中确实有效,只是在测试中没有。

有谁知道如何让这些方面着火?

谢谢!

4

3 回答 3

7

好的..所以解决方案最终出现了......你猜对了......阅读文档:/

http://docs.spring.io/spring-framework/docs/3.2.0.BUILD-SNAPSHOT/reference/htmlsingle/#spring-mvc-test-framework

此外,您可以通过 Spring 配置将模拟服务注入控制器,以便继续专注于测试 Web 层。

所以最终的解决方案是这样的:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = {"testContext.xml","../path/to/applicationContext.xml"})
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
public class MyControllerTest {

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext wac;

    @Autowired
    private MyService myService;    

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    @Test
    public void myTest() {
        MyRequest request = new MyRequest();
        MyResponse response = new MyResponse();
        String expectedValue = "foobar";

        Mockito.when(myService.doSomething((MyRequest) Mockito.any())).thenReturn(response);

        MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.post("/myendpoint");

        String request = IOUtils.toString(context.getResource("classpath:/request.json").getURI());

        builder.content(request);
        builder.contentType(MediaType.APPLICATION_JSON);

        mockMvc.perform(builder)
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.someKey").value(expectedValue));

        Mockito.verify(myService, Mockito.times(1)).doSomething((MyRequest) Mockito.any());
    }
}

然后,您只需为此测试定义一个testContext.xml包含服务对象模拟的上下文文件:

<bean id="myService" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.mypackage.MyService"/>
</bean>

重要的是 MyService 实例已@Autowired进入测试,因此可以对其进行编排。

这允许您模拟任何您喜欢的实例,无论它们是在服务类、方面等中,只要您适当地命名 bean。所以在这种情况下,MyService将被声明为:

@Component("myService")
public class MyService {
...
于 2013-10-30T21:36:58.570 回答
0

我有一个类似的设置,使用 MockMVC 通过层执行集成测试。在我重命名注释的包之前,注释工作正常,没有任何额外的代码。它停止工作。注释不会执行。敲了一阵头后,我意识到我已经解决了一次:ComponentScan the annotation's package。

您可能在其中一个应用程序的配置类文件中有类似的声明。您将需要在您的测试类中重复任何这些类型的声明。

@SpringBootTest
@AutoConfigureMockMvc
@ComponentScan("annotation.package")
public class MyControllerTest {

}
于 2021-02-18T22:55:16.903 回答
0

您需要在测试中启用 aop:

@EnableAspectJAutoProxy
@RunWith(SpringJUnit4ClassRunner.class)
public class MyControllerTest {

}
于 2021-08-05T02:49:06.750 回答