SpringMVC 单元测试 - 服务方法未被调用
SpringMVC Unit testing - Service method is not called
当我 运行 通过模拟服务 bean 在控制器上进行单元测试时,看起来服务方法根本没有被调用。这是预期的行为还是我遗漏了什么?
SearchController.java
@Controller
public class SearchController {
@Autowired
SearchService searchService;
@RequestMapping(value="/search", method=RequestMethod.GET)
public String showSearchPage(Model model){
model.addAttribute("list", searchService.findAll());
return "search";
}
}
SearchControllerTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/webapp/WEB-INF/springapp-servlet.xml")
public class SearchControllerTest {
@Autowired
private WebApplicationContext webAppContext;
private MockMvc mockMvc;
private SearchService searchServiceMock;
@Before
public void setUp(){
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webAppContext).build();
this.searchServiceMock = Mockito.mock(SearchServiceImpl.class);
}
@Test
public void testShowSearchPage() throws Exception{
when(searchServiceMock.findAll())
.thenReturn(Arrays.asList("abc", "acb", "123"));
this.mockMvc.perform(get("/search.do"))
.andExpect(status().isOk())
.andExpect(view().name("search"))
.andExpect(forwardedUrl("/WEB-INF/jsp/search.jsp"))
.andExpect(model().attribute("list", hasSize(3)));
verify(searchServiceMock, times(1)).findAll(); //this test is failing
verifyNoMoreInteractions(searchServiceMock);
}
}
当我 运行 测试时,似乎没有调用 findAll() 方法,它正在抛出异常。 "Wanted but not invoked searchServiceImpl.findAll()"
我在这里犯了什么错误?
------------更新-----------------
SearchControllerTestNew.java
public class SearchControllerTestNew {
@InjectMocks
SearchController searchController;
@Mock
SearchService searchServiceMock;
@Mock
View mockView;
MockMvc mockMvc;
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(searchController).setSingleView(mockView)
.build();
}
@Test
public void testShowSearchPage() throws Exception{
when(searchServiceMock.findAll())
.thenReturn(Arrays.asList("abc", "acb", "123"));
this.mockMvc.perform(get("/search.do"))
.andExpect(status().isOk())
.andExpect(view().name("search"))
.andExpect(model().attribute("list", hasSize(3)))
.andExpect(forwardedUrl("/WEB-INF/jsp/search.jsp"));//this fails now
verify(searchServiceMock, times(1)).findAll();
verifyNoMoreInteractions(searchServiceMock);
}
}
尽管您嘲笑了 SearchService
,但它并未注入控制器(至少从您共享的代码中看不出来)。
因此 verify(searchServiceMock, times(1)).findAll();
注定会失败,因为它确实从未被调用过。
看看 @InjectMock 模拟是如何注入的。
您还需要添加以下 LOC 才能使整个工作正常进行
先介绍一个领域
@InjectMocks
private SearchController controller;
setUp()
中的第二个添加
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
你的 SearchController
将使用自动装配的 SearchService
(应用程序上下文的一部分)而不是你的模拟,注意你创建了一个模拟但你没有在任何地方使用它,而是创建了一个 MockMvc
基于您的应用程序上下文。
一个解决方案是,使用独立设置,让您完全控制控制器及其依赖项的实例化和初始化:
@Before
public void setUp(){
this.searchServiceMock = Mockito.mock(SearchServiceImpl.class);
mockMvc = MockMvcBuilders.standaloneSetup(new SearchController(seachServiceMock))
.setViewResolvers(viewResolver())
.build();
}
private ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
我在此示例中省略了一些 MVC 基础结构配置,请查看 MockMvcBuilder
文档以了解更多配置。
您可以使用 @MockBean
进行模拟,然后它们将自动注入到 Context。
当我 运行 通过模拟服务 bean 在控制器上进行单元测试时,看起来服务方法根本没有被调用。这是预期的行为还是我遗漏了什么?
SearchController.java
@Controller
public class SearchController {
@Autowired
SearchService searchService;
@RequestMapping(value="/search", method=RequestMethod.GET)
public String showSearchPage(Model model){
model.addAttribute("list", searchService.findAll());
return "search";
}
}
SearchControllerTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("file:src/main/webapp/WEB-INF/springapp-servlet.xml")
public class SearchControllerTest {
@Autowired
private WebApplicationContext webAppContext;
private MockMvc mockMvc;
private SearchService searchServiceMock;
@Before
public void setUp(){
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webAppContext).build();
this.searchServiceMock = Mockito.mock(SearchServiceImpl.class);
}
@Test
public void testShowSearchPage() throws Exception{
when(searchServiceMock.findAll())
.thenReturn(Arrays.asList("abc", "acb", "123"));
this.mockMvc.perform(get("/search.do"))
.andExpect(status().isOk())
.andExpect(view().name("search"))
.andExpect(forwardedUrl("/WEB-INF/jsp/search.jsp"))
.andExpect(model().attribute("list", hasSize(3)));
verify(searchServiceMock, times(1)).findAll(); //this test is failing
verifyNoMoreInteractions(searchServiceMock);
}
}
当我 运行 测试时,似乎没有调用 findAll() 方法,它正在抛出异常。 "Wanted but not invoked searchServiceImpl.findAll()"
我在这里犯了什么错误?
------------更新-----------------
SearchControllerTestNew.java
public class SearchControllerTestNew {
@InjectMocks
SearchController searchController;
@Mock
SearchService searchServiceMock;
@Mock
View mockView;
MockMvc mockMvc;
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(searchController).setSingleView(mockView)
.build();
}
@Test
public void testShowSearchPage() throws Exception{
when(searchServiceMock.findAll())
.thenReturn(Arrays.asList("abc", "acb", "123"));
this.mockMvc.perform(get("/search.do"))
.andExpect(status().isOk())
.andExpect(view().name("search"))
.andExpect(model().attribute("list", hasSize(3)))
.andExpect(forwardedUrl("/WEB-INF/jsp/search.jsp"));//this fails now
verify(searchServiceMock, times(1)).findAll();
verifyNoMoreInteractions(searchServiceMock);
}
}
尽管您嘲笑了 SearchService
,但它并未注入控制器(至少从您共享的代码中看不出来)。
因此 verify(searchServiceMock, times(1)).findAll();
注定会失败,因为它确实从未被调用过。
看看 @InjectMock 模拟是如何注入的。
您还需要添加以下 LOC 才能使整个工作正常进行
先介绍一个领域
@InjectMocks
private SearchController controller;
setUp()
中的第二个添加
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
你的 SearchController
将使用自动装配的 SearchService
(应用程序上下文的一部分)而不是你的模拟,注意你创建了一个模拟但你没有在任何地方使用它,而是创建了一个 MockMvc
基于您的应用程序上下文。
一个解决方案是,使用独立设置,让您完全控制控制器及其依赖项的实例化和初始化:
@Before
public void setUp(){
this.searchServiceMock = Mockito.mock(SearchServiceImpl.class);
mockMvc = MockMvcBuilders.standaloneSetup(new SearchController(seachServiceMock))
.setViewResolvers(viewResolver())
.build();
}
private ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
我在此示例中省略了一些 MVC 基础结构配置,请查看 MockMvcBuilder
文档以了解更多配置。
您可以使用 @MockBean
进行模拟,然后它们将自动注入到 Context。