如何正确模拟 ObjectMapper 对象
How to correctly mock an ObjectMapper object
我很难嘲笑 com.fasterxml.jackson.databind.ObjectMapper
。
特别是这个 class 我想测试:
@Service
public class ClassToBeTested {
private final ObjectMapper mapper;
public ClassToBeTested(ObjectMapper mapper) {
this.mapper = mapper;
}
public void publicMethod(messageDto dto) throws JsonProcessingException {
try{
privateMethod(dto, param, "other string");
} catch(JsonProcessingException e){
// do stuff
}
}
private void privateMethod(Object dto, String param, String param2) {
Map<String, Object> attributes = new HashMap<>();
attributes.putAll(mapper.readValue(mapper.writeValueAsString(dto),
new TypeReference<Map<String, Object>>() {
}));
attributes.put("level", "error");
//other stuff
}
}
我的测试class:
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = TestContextConfiguration.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class ClassToBeTestedTest {
@MockBean
private ObjectMapper mapper;
private ClassToBeTested classToBeTestedActor;
@PostConstruct
public void initMock() throws JsonProcessingException {
when(mapper.writeValueAsString(any())).thenReturn(any());
when(mapper.readValue(anyString(), Mockito.<TypeReference<Map<String,
Object>>>any())).thenReturn(new HashMap<>());
}
@Before
public void setup() {
classToBeTestedActor = new ClassToBeTested(mapper);
}
@Test
public void shouldFailJsonParsing() throws JsonProcessingException {
// Given
final Dto dto = mock(Dto.class);
// When
when(mapper.writeValueAsString(any()))
.thenThrow(JsonProcessingException.class);
// Then
Assertions.assertThrows(JsonProcessingException.class,
() -> classToBeTestedActor.publicMethod(dto));
}
}
目的是触发和测试JsonProcessingException
。由于 InvalidUseOfMatchersException
:
测试失败
Invalid use of argument matchers!
2 matchers expected, 3 recorded:
-> at com.ocado.crm.service.ClassToBeTestedTest.initMock(ClassToBeTestedTest.java:47)
-> at com.ocado.crm.service.ClassToBeTestedTest.initMock(ClassToBeTestedTest.java:48)
-> at com.ocado.crm.service.ClassToBeTestedTest.initMock(ClassToBeTestedTest.java:48)
其中第46行和第47行分别是:
when(mapper.writeValueAsString(any())).thenReturn(any());
when(mapper.readValue(anyString(), Mockito.<TypeReference<Map<String, Object>>>any()))
.thenReturn(new HashMap<>());
这对我来说毫无意义,因为我认为我没有混合匹配器和原始值。
我怎样才能正确模拟 ObjectMapper
以便我可以测试 JsonProcessingException
?
我不明白编写模拟 Object Mapper 抛出一些异常然后测试是否抛出异常的测试背后的原因。相反,测试应该针对您开发的自定义逻辑。如果你有这样的方法 -
public void publicMethod(messageDto dto) {
try{
privateMethod(dto, param, "other string");
} catch(JsonProcessingException e){
// do stuff
dto.setXXX("XXX"); // The test should be testing this
}
}
所以,测试应该是测试dto是否设置正确。
@Test
public void shouldFailJsonParsing() throws JsonProcessingException {
// Given
final Dto dto = new Dto();
// When
when(mapper.writeValueAsString(any()))
.thenThrow(JsonProcessingException.class);
// Invoke the method to be tested
classToBeTestedActor.publicMethod(dto);
// Test whether expected mock methods are invoked
verify(mapper, times(1)).writeValueAsString(any());
verifyNoMoreInteractions(mapper);
// Assert results
Assert.assertEquals("XXX", dto.getXXX());
}
I get your point and I kind of agree with that. I just want to
understand why, even if I am forcing the mapper to throw that
exception, I am unable to assert it
我觉得是因为异常被你捕获了。这就是该异常不会传播到您的测试的原因。
public void publicMethod(messageDto dto) throws JsonProcessingException {
try{
privateMethod(dto, param, "other string");
} catch(JsonProcessingException e){
// do stuff
}
}
尝试将其更改为 -
public void publicMethod(messageDto dto) throws JsonProcessingException {
privateMethod(dto, param, "other string");
}
我很难嘲笑 com.fasterxml.jackson.databind.ObjectMapper
。
特别是这个 class 我想测试:
@Service
public class ClassToBeTested {
private final ObjectMapper mapper;
public ClassToBeTested(ObjectMapper mapper) {
this.mapper = mapper;
}
public void publicMethod(messageDto dto) throws JsonProcessingException {
try{
privateMethod(dto, param, "other string");
} catch(JsonProcessingException e){
// do stuff
}
}
private void privateMethod(Object dto, String param, String param2) {
Map<String, Object> attributes = new HashMap<>();
attributes.putAll(mapper.readValue(mapper.writeValueAsString(dto),
new TypeReference<Map<String, Object>>() {
}));
attributes.put("level", "error");
//other stuff
}
}
我的测试class:
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = TestContextConfiguration.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class ClassToBeTestedTest {
@MockBean
private ObjectMapper mapper;
private ClassToBeTested classToBeTestedActor;
@PostConstruct
public void initMock() throws JsonProcessingException {
when(mapper.writeValueAsString(any())).thenReturn(any());
when(mapper.readValue(anyString(), Mockito.<TypeReference<Map<String,
Object>>>any())).thenReturn(new HashMap<>());
}
@Before
public void setup() {
classToBeTestedActor = new ClassToBeTested(mapper);
}
@Test
public void shouldFailJsonParsing() throws JsonProcessingException {
// Given
final Dto dto = mock(Dto.class);
// When
when(mapper.writeValueAsString(any()))
.thenThrow(JsonProcessingException.class);
// Then
Assertions.assertThrows(JsonProcessingException.class,
() -> classToBeTestedActor.publicMethod(dto));
}
}
目的是触发和测试JsonProcessingException
。由于 InvalidUseOfMatchersException
:
Invalid use of argument matchers!
2 matchers expected, 3 recorded:
-> at com.ocado.crm.service.ClassToBeTestedTest.initMock(ClassToBeTestedTest.java:47)
-> at com.ocado.crm.service.ClassToBeTestedTest.initMock(ClassToBeTestedTest.java:48)
-> at com.ocado.crm.service.ClassToBeTestedTest.initMock(ClassToBeTestedTest.java:48)
其中第46行和第47行分别是:
when(mapper.writeValueAsString(any())).thenReturn(any());
when(mapper.readValue(anyString(), Mockito.<TypeReference<Map<String, Object>>>any()))
.thenReturn(new HashMap<>());
这对我来说毫无意义,因为我认为我没有混合匹配器和原始值。
我怎样才能正确模拟 ObjectMapper
以便我可以测试 JsonProcessingException
?
我不明白编写模拟 Object Mapper 抛出一些异常然后测试是否抛出异常的测试背后的原因。相反,测试应该针对您开发的自定义逻辑。如果你有这样的方法 -
public void publicMethod(messageDto dto) {
try{
privateMethod(dto, param, "other string");
} catch(JsonProcessingException e){
// do stuff
dto.setXXX("XXX"); // The test should be testing this
}
}
所以,测试应该是测试dto是否设置正确。
@Test
public void shouldFailJsonParsing() throws JsonProcessingException {
// Given
final Dto dto = new Dto();
// When
when(mapper.writeValueAsString(any()))
.thenThrow(JsonProcessingException.class);
// Invoke the method to be tested
classToBeTestedActor.publicMethod(dto);
// Test whether expected mock methods are invoked
verify(mapper, times(1)).writeValueAsString(any());
verifyNoMoreInteractions(mapper);
// Assert results
Assert.assertEquals("XXX", dto.getXXX());
}
I get your point and I kind of agree with that. I just want to understand why, even if I am forcing the mapper to throw that exception, I am unable to assert it
我觉得是因为异常被你捕获了。这就是该异常不会传播到您的测试的原因。
public void publicMethod(messageDto dto) throws JsonProcessingException {
try{
privateMethod(dto, param, "other string");
} catch(JsonProcessingException e){
// do stuff
}
}
尝试将其更改为 -
public void publicMethod(messageDto dto) throws JsonProcessingException {
privateMethod(dto, param, "other string");
}