#java #unit-testing #junit #mockito
#java #модульное тестирование #junit #mockito
Вопрос:
Мне трудно издеваться над com.fasterxml.jackson.databind.ObjectMapper
.
В частности, это класс, который я хочу протестировать:
@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
}
}
Мой тестовый класс:
@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
?
Комментарии:
1. строка 46 -Аргумент метода thenReturn не ожидает сопоставления. Попробуйте заменить его, скажем, thenReturn(«someJSON»)
2. вы были правы. в этом проблема! Тем не менее, исключение JsonProcessingException не генерируется. У вас есть какие-либо идеи?
3. publicMethod улавливает исключение. Даже если макет выдает исключение, утверждение завершится ошибкой.
4. вы имеете в виду, что я должен перехватить его в privateMethod, чтобы добиться успеха assert? Потому что я пытался поймать его и в частном методе с теми же результатами
5. Я забыл добавить его при копировании кода. publicMethod действительно вызывает исключение JsonProcessingException в подписи. Тем не менее тест проваливается
Ответ №1:
Я не вижу причины для написания теста, который издевается над 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());
}
Я понимаю вашу точку зрения, и я отчасти согласен с этим. Я просто хочу
поймите, почему, даже если я заставляю mapper выбрасывать это
исключение, я не могу утверждать это
Я думаю, причина этого в том, что исключение перехватывается вами. Это причина, по которой это исключение не распространяется на ваш тест.
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");
}