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。

文档:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing-spring-boot-applications-mocking-beans