【问题标题】:Unit test for JsonProcessingExceptionJsonProcessingException 的单元测试
【发布时间】:2017-09-15 15:04:00
【问题描述】:

我想编写一个单元测试来测试 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);
        } 
}

这是我的单元测试:

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...);
    }

}

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

【问题讨论】:

    标签: java json unit-testing mocking mockito


    【解决方案1】:

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

     public void myMethod() {
            try {
                ObjectMapper mapper = new ObjectMapper();
             ...
    }
    

    所以,@InjectMocks 会很无奈。

    我可以给你两个选择:

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

     public void myMethod(ObjectMapper mapper) {
      ...
     }
    

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

    如果经常调用此方法,传递样板参数可能会很烦人,并且会降低代码的可读性。

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

    public class ClassUnderTest{
    
       private ObjectMapper objectMapper;
       ...
       public ClassUnderTest(ObjectMapper objectMapper){
          this.objectMapper = objectMapper;
      }
      ...
    }
    

    【讨论】:

    • 是的,这是真的。但是,我想在不更改似乎不可能的课程的情况下找到解决方案..
    • 有了mocking,确实是不可能的。但作为替代方案,您可以在不模拟 ObjectMapper 的情况下测试此类。您应该只传递会引发异常的东西作为测试方法的参数。
    • 嗯,new ObjectMapper() 很容易被嘲笑,但你是对的,测试首先不应该嘲笑任何东西。事实上,通过传入一个没有注册序列化程序的testObject,应该很容易导致mapper.writeValueAsString(testObject) 调用抛出异常。在此处使用模拟只会导致与 SUT 的实现紧密耦合的糟糕测试。
    【解决方案2】:

    要使用 ObjectMapper 测试方法并抛出自定义异常(包装 JsonProcessingException),我们需要模拟 ObjectMapper 并告诉它抛出异常。

    这是一个具有解析 JsonNode 并抛出自定义异常的方法的类:

    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import lombok.RequiredArgsConstructor;
    
    @RequiredArgsConstructor
    public class MyService {
    
        private final ObjectMapper objectMapper;
    
        public Boolean processSomething(JsonNode jsonNode) {
    
            Simple simple;
            try {
                simple = objectMapper.readValue(jsonNode.toString(), Simple.class);
            } catch (JsonProcessingException e) {
                throw new CustomServerException(e.getMessage(), e);
            }
            return true;
        }
    }
    

    测试这个方法:

    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.my.path.MyService;
    import org.assertj.core.api.Assertions;
    import org.mockito.Mockito;
    import org.testng.annotations.Test;
    
    public class TestMyService {
        // To test the method for the CustomServerException,
        // we need to mock the ObjectMapper to throw the JsonProcessingException:
        @Test
        void testProcessSomething_JsonProcessingException() {
    
            // using a mock ObjectMapper to force a JsonProcessingException to be thrown
            ObjectMapper mockMapper = Mockito.mock(ObjectMapper.class);
            MyService serviceWithMockMapper = new MyService(mockMapper);
    
            CustomServerException thrown = assertThrows(CustomServerException.class, () -> {
    
                when(mockMapper.readValue(jsonNode.toString(), Simple.class)).thenThrow(JsonProcessingException.class);
                serviceWithMockMapper.processSomething(jsonNode);
    
            });
    
            Assertions.assertNotNull(thrown.getMessage());
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      相关资源
      最近更新 更多