Модульное тестирование метода, который обновляет только некоторые свойства

#java #unit-testing

#java #модульное тестирование

Вопрос:

Я хочу модульно протестировать метод, который установил для свойства active класса Person значение True.

Класс Person обладает многими другими свойствами :

 public class Person{
    private int id;
    private Boolean active;
    private Boolean adu<
    ... more properties

    ... getters and setters
}
  

Тестируемый метод будет выглядеть примерно так :

 public void updatePersonStatus(int personId){
    Person person = getPersonById(personId);
    person.setActive(true);

    repository.save(person);
}
  

Достаточно ли проверить только то, что метод save вызывается с объектом person, у которого есть свойство active true (пример использования mockito):

     @Test
    public void activateTest() {
        ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);
        Person testPerson = new Person();
        testPerson.setActif(true);

        responsableExamenService.updatePersonStatus(1);

        verify(theClass, times(1)).save(argument.capture()); //verify that the method save is called one time with a class Person as a parameter
        assertTrue(argument.getValue().getActive()); //and that the Object person have a property active to true.
    }
  

Или мне также нужно проверить, что все остальные свойства Person не были изменены bean?

Итак, другими словами, нужно ли модульному тестированию проверять, «что должен делать метод», или ему нужно проверять только то, что должен делать метод, без проверки возможных побочных эффектов? Здесь примером побочного эффекта может быть помимо установки active значения true, разработчик также может установить для свойства adult значение true.

PS: Пример приведен на Java, но вопрос актуален почти для каждого языка программирования

Ответ №1:

К сожалению, набор вещей, которые функция не должна выполнять, бесконечен. Не устанавливать другие атрибуты, кроме желаемых, — это только одна из возможностей. И, когда дело доходит до спецификаций, они в основном являются явными только в отношении того, что должна делать функция. Всегда присутствует неявное «и больше ничего», и лишь в редких случаях некоторые выбранные варианты поведения явно исключаются.

С другой стороны, когда вы применяете модульное тестирование для проверки того, что написанный вами код ведет себя так, как вы предполагаете, тогда проблема становится управляемой: существует набор «вероятных» ошибок, и ваши тесты должны быть разработаны для их обнаружения. Например, вы знаете, выполняет ли ваш код ввод-вывод или нет, и если нет, то нет смысла писать модульные тесты, чтобы убедиться, что он не выполняет ввод-вывод. С другой стороны, если у вас есть веские основания полагать, что вероятная ошибка заключается в том, что код выполняет больше, чем предполагалось для конкретной операции, тогда стоит проверить, чтобы убедиться, что это не так.

То же самое относится, в основном, к коду, написанному каким-то другим человеком, например, если вы берете на себя обслуживание какого-то кода. В любом случае модульное тестирование — это метод тестирования «белого ящика», и предполагается, что у вас есть доступ к коду, обычно даже возможность изменить его (например, для улучшения тестируемости).

Ответ №2:

Простой ответ — строгого правила не существует. Модульное тестирование означает тестирование одной «единицы» функциональности.

В вашем случае функциональностью является «обновление статуса пользователя». Это должно быть определено спецификацией — что ожидается в этом случае. И, в идеальном мире, ваши тесты должны проверять только указанные вещи.

Также неплохо проводить модульное тестирование по одному действию за раз. Например. первый тест может проверять базовую функциональность, а второй — проверять побочные эффекты.

Ответ №3:

Правило, которому я лично следую, заключается в том, чтобы сначала проверить, что должен делать метод. Я протестирую что-то вроде «без побочных эффектов» тогда и только тогда, когда либо имеет смысл с точки зрения реализации метода применить такой эффект (но это не должно), либо (придерживаясь одного из правил TDD), когда я докажу, что код работает (обращаясь к вашему примеру — сначала я бы не стал проверять отсутствие такого побочного эффекта, но если какой-то разработчик установил для другого свойства значение true — я докажу ошибку, написав модульный тест, который проверяет этот побочный эффект, а затем я применю исправление ).