Я новичок в модульном тестировании, и иногда у меня бывают такие ситуации с несколькими условиями. Однако я не уверен, буду ли я повторно издеваться или проверять одни и те же случаи для каждого теста.
Например, я пытаюсь написать модульные тесты для следующего метода службы:
public void create(Request request) {
// code omitted
if (!employeeService.existsByUuid(uuid)) {
throw new EntityNotFoundException("Not found");
}
EmployeeDTO employee = employeeService.save(...);
if (!departmentService.existsByUuid(employee.getDepartment())) {
throw new EntityNotFoundException("Not found");
}
}
Я думаю, что мне нужно написать свои тесты для следующих сценариев:
1., когда employeeService.existsByUuid(uuid) == false, затем создайте новое исключение EntityNotFoundException. затем убедитесь, что employeeService.save() и departmentService.existsByUuid() никогда не вызываются.
2. когда employeeService.existsByUuid(uuid) == true вызывается employeeService.save() и я утверждаю значения. а затем убедитесь, что employeeService.save() и departmentService.existsByUuid() никогда не вызываются.
3., когда departmentService.existsByUuid() == false, затем создайте новое исключение EntityNotFoundException. На этом этапе я также имитирую employeeService.existsByUuid(uuid) как true, чтобы тест прошел первое условие. Однако я не уверен, нужно ли мне утверждать вторую часть; employeeService.save() вызывается, и я утверждаю ценности. Утверждаю ли я возвращаемые значения или просто проверяю, что метод вызывается 1 раз. Потому что я уже утверждал его значение, а 3-й тест как раз для 3-го условия.
Любая идея для такого рода сценариев, когда у нас есть несколько условий и может потребоваться повторное тестирование одного и того же условия снова и снова?
@QBrute Спасибо, но я имею в виду не общие вещи, которые можно собрать в разделе @Before. Итак, вы имеете в виду, что мне нужно выполнять утверждения для части employeeService.save(), даже если я проверяю первое или третье условие? Или просто проверьте, называется он или нет в зависимости от ситуации. Есть идеи?




Вы не должны пытаться тестировать свой код построчно, но с случаями, которые охватывают один осмысленный сценарий. Поэтому, если у вас уже есть кейс, проверяющий условие, вам не нужно повторять эти утверждения в других тестовых кейсах.
В вашем примере я думаю, что это могут быть основные случаи:
Чтобы проверить их, вы можете сделать что-то вроде этого:
EmployeeService employeeService = mock(EmployeeService.class);
Дело 1:
when(employeeService.existsByUuid(employeeUuid)).thenReturn(false);
try {
testObject.create(request);
fail();
}
catch(EntityNotFoundException e) {
verify(employeeService, never()).save(...);
}
случай 2:
when(employeeService.existsByUuid(employeeUuid)).thenReturn(true);
when(employeeService.existsByUuid(departmentUuid)).thenReturn(true);
testObject.create(request);
verify(employeeService).save(field1, field2, ...);
случай 3:
when(employeeService.existsByUuid(employeeUuid)).thenReturn(true);
when(employeeService.existsByUuid(departmentUuid)).thenReturn(false);
try {
testObject.create(request);
fail();
}
catch(EntityNotFoundException e) {
// success
}
Кстати, вы также можете указать ожидаемые исключения в аннотации @Test, но тогда вы не сможете выполнять дальнейшую проверку результатов:
@Test(expected = EntityNotFoundException.class)
public void test3() {
when(employeeService.existsByUuid(employeeUuid)).thenReturn(true);
when(employeeService.existsByUuid(departmentUuid)).thenReturn(false);
testObject.create(request);
}
Вы имеете в виду, что я НЕ нужно выполняю утверждения для части employeeService.save(), когда я проверяю первое или третье условие, и просто проверяю, вызывается ли employeeService.save() или нет (в соответствии с условием), когда я проверяю первое или третье условие. Есть идеи?
Я думаю, что для первого случая важным требованием является то, чтобы сотрудник НЕ был спасен. Во втором случае следует проверить, что сотрудник сохранен ПРАВИЛЬНО. А для третьего случая экономия не актуальна.
Большое спасибо, сначала я не использую try-catch, а просто использую нотацию JUnit5 для тестирования исключений. Пункты, в которых я не уверен, перечислены ниже, не могли бы вы разъяснить мне один за другим?
1. Проверка неплохая, но иногда и не нужная. Например, в случае 1, employeeService заглушен, чтобы вернуть «false», и мы ожидаем, что код выдаст исключение. Если происходит исключение, поведение соответствует ожидаемому. Никаких дополнительных проверок там делать не нужно. Но для действия сохранения мы хотим явно убедиться, что оно НЕ вызывается, поэтому нам нужно это проверить.
2. Старайтесь, чтобы каждый тестовый пример был как можно более целенаправленным (при этом сохраняя его удобочитаемость). Нет необходимости повторять утверждения или проверки, которые не нужны для этого конкретного случая.
Дополнительный бесплатный совет: если ваш код создает новый экземпляр и передает его в одну из своих зависимостей, вы можете проверить значения с помощью ArgumentCaptor.
Что касается try-catch, то он нужен в случае 1, потому что вы хотите что-то проверить ПОСЛЕ того, как было выброшено исключение. Если вы используете аннотацию, то никаких дополнительных проверок, как я уже упоминал, выполнять нельзя. Для случая 3 можно обойтись без try-catch.
Я использую ArgumentCaptor, но много публикую здесь, чтобы упростить код. Большое спасибо, амиго, очень полезный ответ и комментарии.
Любая помощь о Эта проблема?
Есть комментарий, в котором говорится то же самое, что я упомянул: «вам нужно поймать исключение и выполнить утверждения после» (stackoverflow.com/questions/48746002/…)
Спасибо, но я не предпочитаю использовать try-catch и думаю, что может быть другая альтернатива. Есть идеи?
Вы можете использовать assertThrows, как объяснил HariHaravelan
Вы также можете использовать правило ExpectedException. Обзор см. в этой статье: blog.aspiresys.pl/технологии/….
Вы можете использовать mockito для проверки и утверждения бросков, чтобы проверить свои цели, как показано ниже.
@Test
public void testOne(){
when(employeeService.existsByUuid(uuid)).thenReturn(false);
assertThrows(EntityNotFoundException.class, () -> {
create(request);
});
verify(employeeService, times(0)).save(eq(empObj));
verify(departmentService, times(0)).existsByUuid(eq(departmentObj));
}
@Test
public void testTwo(){
when(employeeService.existsByUuid(uuid)).thenReturn(true);
when(departmentService.existsByUuid(uuid)).thenReturn(true);
create(request);
verify(employeeService, times(1)).save(eq(empObj));
verify(departmentService, times(1)).existsByUuid(eq(departmentObj));
}
@Test
public void testThree(){
when(employeeService.existsByUuid(uuid)).thenReturn(true);
when(departmentService.existsByUuid(uuid)).thenReturn(false);
assertThrows(EntityNotFoundException.class, () -> {
create(request);
});
verify(employeeService, times(1)).save(eq(empObj));
verify(departmentService, times(1)).existsByUuid(eq(departmentObj));
}
В идеале вы должны написать один отдельный тест для каждого отдельного сценария. Для вещей, которые необходимо настраивать каждый раз, вы можете использовать
@Beforeв своем тестовом классе.