Reputation: 307
HelloController.java
@RestController
class HelloController {
@GetMapping(value = "{id}/hello")
public ModelAndView listAPI(@PathVariable("id") String profileId) {
ModelAndView mav = new ModelAndView();
return mav;
}
}
HelloControllerTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = HelloConfigTest.class)
class HelloControllerTest {
@Inject
private WebApplicationContext webApplicationContext;
@Inject
private Foo mockFoo
@InjectMocks
HelloController helloController;
private MockMvc mockMvc;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void testHello() throws Exception {
mockMvc.perform(
get("/{id}/campaigns", "id1"))
.andExpect(status().isOk()));
}
}
// I have another test that directly calls the controller method.
// So I need @InjectMocks to get an instance of the controller
@Test
public void test2() {
when(mockFoo.getX()).thenReturn(true);
helloController.saveAPI();
}
HelloConfigTest.java
@Configuration
@ComponentScan("com.test.controller")
class HelloConfigTest {
@Bean
public mockFoo() {
return Mockito.mock(Foo.class);
}
}
The response that I get here is 404 and I expect 200.
But it works and I get 200 if I change @GetMapping to @RequestMapping(value="{id}/hello", method=RequestMethod.GET)
Am I missing anything here ?
Upvotes: 4
Views: 1927
Reputation: 280102
Your configuration is extremely bare bones
@Configuration
@ComponentScan("com.test.controller")
class HelloConfigTest {
It doesn't register any Spring MVC infrastructure beans, either implicitly or explicitly.
When MockMvc
, internally, creates a TestDispatcherServlet
to test your @Controller
class, it has to defer to some default Spring MVC infrastructure types.
Among these infrastructure types is HandlerMapping
which is
to be implemented by objects that define a mapping between requests and handler objects.
The default implementation used by the TestDispatcherSerlet
is DefaultAnnotationHandlerMapping
(an old class) which looks for @RequestMapping
specifically, it doesn't recursively do a meta-annotation lookup. Your @GetMapping
annotated method is therefore not found and not registered as a handler.
If, instead, you configure your application context with @EnableWebMvc
@Configuration
@ComponentScan("com.test.controller")
@EnableWebMvc
class HelloConfigTest {
Spring will implicitly register a RequestMappingHandlerMapping
, which does do this "recursive" lookup for the annotation hierarchy (called merging). Since @GetMapping
is annotated with @RequestMapping
, the annotated handler method will be found and registered.
As for the @InjectMocks
, note that the instance referenced by the field is different from the one used to handle the request performed by the MockMvc
object. The former is managed by Mockito, the latter by Spring.
Upvotes: 4