当方法使用ObjectMapper.writeValueAsString时,如何使用模拟编写单元测试

时间:2016-11-11 13:21:32

标签: java unit-testing mocking mockito

我有一个SpringMVC项目。我要测试的我的FooController方法是:

@GetMapping("/view/{fooId}")
public String view(@PathVariable String fooId, Model model) throws FooNotFoundException, JsonProcessingException {
    Foo foo = fooService.getFoo(fooId);
    model.addAttribute("fooId", foo.getId());
    model.addAttribute("foo", new ObjectMapper().writeValueAsString(foo));
    return "foo/view";
}

我写的测试是:

public class FooControllerTest {
    @Mock
    private Foo mockFoo;
    @Mock
    private FooService mockFooService;
    @InjectMocks
    private FooController controller;
    private MockMvc mockMvc;

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

    @Test
    public void testView() throws Exception {
        String fooId = "fooId";
        when(mockFooService.getFoo(fooId)).thenReturn(mockFoo);
        when(mockFoo.getId()).thenReturn(fooId);

        mockMvc.perform(get("/foo/view/" + fooId))
                .andExpect(status().isOk())
                .andExpect(model().attribute("fooId", fooId))
                .andExpect(model().attributeExists("foo"))
                .andExpect(forwardedUrl("foo/view"));
    }

}

此测试失败,java.lang.AssertionError: No ModelAndView found。 当我调试测试时,当mockFoonew ObjectMapper.writeValueAsString()给出时,我发现它出错了。所以我认为模拟对象无法序列化。我该如何解决这个问题,如何让我的测试通过?

<小时/> 我已经尝试了什么:

  • 我评论了FooController中的行model.addAttribute("foo", new ObjectMapper().writeValueAsString(foo));,这样测试工作(但不是我希望我的方法工作的方式)!所以现在我知道这是出错的地方。
  • 我评论了FooControllerTest中的行.andExpect(model().attributeExists("foo")),它仍然产生了上述AssertionError。
  • 谷歌搜索和StackOverflowing,但我可以找到一些可用的东西。

2 个答案:

答案 0 :(得分:0)

一位同事建议如下:不是使用mockFoo,而是创建一个新的Foo对象并像这样使用它:

@Test
public void testView() throws Exception {
    String fooId = "fooId";
    Foo foo = new Foo(fooId);
    when(mockFooService.getFoo(fooId)).thenReturn(foo);

    mockMvc.perform(get("/foo/view/" + fooId))
            .andExpect(status().isOk())
            .andExpect(model().attribute("fooId", fooId))
            .andExpect(model().attributeExists("foo"))
            .andExpect(forwardedUrl("foo/view"));
}

这很有效。我一直认为你必须模拟你没有测试过的每个对象(所以在Controller中,你会模拟除控制器本身之外的所有东西)。但是因为Foo是一个简单的POJO,所以不需要嘲笑它。

答案 1 :(得分:0)

在执行InjectMocks注释时尝试添加Spy注释

@InjectMocks
@Spy
private FooController controller;

是的,不要实例化ObjectMapper或控制器内的任何类。如果你这样做,你将被迫使用PowerMockito。尝试在@Ruben提及的控制器中注入它们。

注入依赖项总是更容易进行测试。