Пружинный аспект не срабатывает в модульном тесте
Хорошо, мы говорим о 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), не выполняется. Это выполняется просто отлично, когда конечная точка инициируется реальным запросом (например, при запуске в контейнере сервлета), но просто не стреляет при запуске в тесте.
Является ли это особой "особенностью" MockMvc, что она не запускает аспекты?
К вашему сведению наш applicationContext.xml настраивается с помощью:
<aop:aspectj-autoproxy/>
И, как я уже упоминал, аспекты действительно работают в реальности, только не в тесте.
Кто-нибудь знает, как заставить эти аспекты выстрелить?
Спасибо!
1 ответ:
Хорошо.. так что решение в конце концов представилось само собой.. вы сами догадались.. чтение документации: /
Кроме того, вы можете внедрить макетные сервисы в контроллеры через конфигурацию Spring, чтобы оставаться сосредоточенным на тестировании веб-слоя.
Таким образом, окончательное решение выглядит следующим образом:
@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
в тесте, поэтому его можно организовать.Это позволяет вам имитировать любые экземпляры, которые вам нравятся, независимо от того, находятся ли они в классах обслуживания, аспектах и т. д., Пока вы называете Боб соответствующим образом. Таким образом, в этом случае
MyService
будет объявлено как:@Component("myService") public class MyService { ...