JsonProcessingException 的单元测试

orc*_*ser 5 java json unit-testing mocking mockito

我想编写一个单元测试来测试 JsonProcessingException。此异常可能发生在以下行:mapper.writeValueAsString()。

public void myMethod(Args...) {
        try {
               ObjectMapper mapper = new ObjectMapper();
                mapper.configure(SerializationFeature.INDENT_OUTPUT, true);

                Document.parse(mapper.writeValueAsString(testObject)));
            }
        } catch (JsonProcessingException e) {
            log.error("Error parsing the object to json string. ", e);
        } 
}
Run Code Online (Sandbox Code Playgroud)

这是我的单元测试:

public class Test {

    @Mock
    private ObjectMapper              mapper;

    @InjectMocks
    ClassUnderTest            sut;

    @Test
    public void testJsonProcessingException() throws     JsonProcessingException {
        when(mapper.writeValueAsString(Mockito.any())).thenThrow(new     JsonProcessingException("Error parsing the object to json string. "){
            private static final long serialVersionUID = 1L;});
        sut.myMethod(args...);
    }

}
Run Code Online (Sandbox Code Playgroud)

问题是我模拟的映射器将不会被使用(我得到不必要的 Mockito 存根失败),因为映射器在方法内部再次初始化。我如何使用mockito对这种情况进行单元测试?

dav*_*xxx 3

mapper不是被测试实例的字段/依赖项。
它是在方法中创建的局部变量:

 public void myMethod() {
        try {
            ObjectMapper mapper = new ObjectMapper();
         ...
}
Run Code Online (Sandbox Code Playgroud)

所以,@InjectMocks才会很无奈。

我可以向您推荐两种选择:

1)您可以mapper通过更改方法的签名作为参数传递:

 public void myMethod(ObjectMapper mapper) {
  ...
 }
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以将模拟ObjectMapper作为测试方法的参数传递。

如果经常调用此方法,则传递样板参数可能会很烦人,并使代码可读性较差。

2)另一种方法是提供一种ObjectMapper通过被测类的构造函数进行设置的方法。

public class ClassUnderTest{

   private ObjectMapper objectMapper;
   ...
   public ClassUnderTest(ObjectMapper objectMapper){
      this.objectMapper = objectMapper;
  }
  ...
}
Run Code Online (Sandbox Code Playgroud)

  • 用mocking来说,确实是不可能的。但作为替代方案,您可以在不模拟“ObjectMapper”的情况下测试此类。您应该只传递一些会引发异常的参数作为被测试方法的参数。 (2认同)
  • 好吧,“new ObjectMapper()” *可以*很容易被嘲笑,但你是对的,测试不应该首先嘲笑任何东西。事实上,通过传入没有注册序列化器的“testObject”,应该很容易导致“mapper.writeValueAsString(testObject)”调用抛出异常。此处使用模拟只会导致与 SUT 的实现紧密耦合的糟糕测试。 (2认同)