Имеет ли смысл использовать методы-оболочки Unittest

Этот вопрос несколько философский. Учитывая, что у меня есть такой метод:

public List<String> getStuffByName(@NotNull String name) throws SomeException {
        return someDependency.createQuery().byName(name).list().stream()
                .map(execution -> execution.getProcessInstanceId())
                .collect(Collectors.toList());
}

По сути, все, что он делает, это вызывает метод зависимостей, а затем обрабатывает его с помощью потокового API.

Unittest — в строгом понимании (?) — тестирует только один изолированный модуль. Поэтому я бы издевался над зависимостями, так как я предполагаю, что они также уже являются протестированными модулями.

Если я пройду через это, я получу метод, который состоит исключительно из вещей, протестированных в другом месте.

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

public void test_get_processes_for_bkey_2(@Mocked ExecutionQuery query,
                                              @Mocked List<String> processes,
                                              @Mocked List<Execution> executions,
                                              @Mocked Stream<Execution> e_stream,
                                              @Mocked Stream<String> pid_stream,
                                              @Mocked Stream<String> pdef_stream

    ) {
    new Expectations() {
        {
            someDependency.createQuery(); result = query;
            query.byName("somefilter"); result = query;
            query.list(); result = executions;
            executions.stream(); result = e_stream;
            e_stream.map((Function) any); result = fin_stream;
            fin_stream.collect((Collector) any); result = processes;
            processes.size(); result = 2;
        }
    };

    assertEquals(tested.getStuffByName("somefilter").size(), 2);
}

Но что этот тест на самом деле говорит мне?

В разработке через тестирование, могу ли я пропустить тесты таких методов «обертки»?

Каким будет профессиональный подход к тестированию, независимо от Jmockit или других фреймворков?


person billdoor    schedule 26.06.2015    source источник


Ответы (4)


«Профессиональный подход» к тестированию заключается в том, чтобы не ничего издеваться над чем-либо. Хороший тест должен быть максимально реалистичным, но при этом достаточно быстрым и стабильным.

Модульные тесты (в чистом/строгом смысле, когда модуль изолируется от своих зависимостей посредством имитации) переоценены. Это говорю не только я; такие авторы, как Кент Бек (главный «создатель» TDD) и Мартин Фаулер, также не являются поклонниками «чистого» модульного тестирования (см. ="noreferrer">Умер ли TDD?, например).

Насмешки лучше всего использовать в исключительных случаях, когда по практическим соображениям вы просто не можете легко написать тест без них. По моему собственному опыту, интеграционные тесты (без насмешек или с минимальным количеством насмешек) оказались намного лучше.

person Rogério    schedule 26.06.2015

Основная идея модульных тестов заключается в том, что они проверяют «единицы» кода, а не всю инфраструктуру или взаимодействие между компонентами. Если вы напишете метод вроде

public int sum(int a, int b){
  return a + b;
}

вы все еще используете обертки (int/Integer и метод +), но в этом случае вы должны написать модульные тесты, чтобы проверить, что ваш < Метод strong>sum работает, не так ли? Потому что вы могли сделать что-то вроде:

public int sum(int a, int b){
  return a;
}

и это точно баг - но все равно это просто обертка!

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

person Markon    schedule 26.06.2015

Контракт метода заключается в выполнении запроса с заданным именем и возврате идентификаторов экземпляров процесса экземпляров Execution, возвращенных запросом. Использует ли ваш метод потоки, цикл for или что-то еще, не имеет значения.

Поэтому я бы только заглушил запрос и заставил его вернуть реальный список из 2 или 3 исполнений. Основываясь на этом списке, возвращенном запросом, я бы проверил, что возвращенный список содержит соответствующие 2 или 3 идентификатора в правильном порядке.

person JB Nizet    schedule 26.06.2015

Вы действительно хотите протестировать все общедоступные методы, в том числе те, которые оборачивают логику других методов. Прохождение модульного теста для этого метода говорит вам о нескольких важных вещах:

  • Метод getStuffByName существует,
  • Подпись getStuffByName - это то, что вы ожидаете,
  • Логика getStuffByName закреплена проверками в модульном тесте.

Если кто-то решит повторно реализовать ваш метод getStuffByName с помощью циклов вместо потоков, потому что он хочет обратно портировать ваш код на более раннюю версию Java, прохождение модульного теста позволит им узнать, что их преобразование работает правильно.

person Sergey Kalinichenko    schedule 26.06.2015