Как проверить метод void перед его реализацией? - PullRequest
0 голосов
/ 03 июня 2018

Я разрабатываю новый проект.Это то, что было сделано до сих пор:

  1. Технический проект.
  2. Классы моделей (классы данных).
  3. Все интерфейсы в проекте (нореализации пока нет).

Следующее, что я хочу сделать, - это реализовать методы от скелета (высокоуровневые методы) до вложенных объектов.Тем не менее, я хочу создать модульный тест для каждого метода, прежде чем писать реализацию.Сначала не возникнет никаких проблем с реализацией методов высокого уровня, потому что я собираюсь работать с интерфейсами и связывать конкретную реализацию только во внешнем файле конфигурации Java с помощью DI.

Первый метод I 'Реализация m называется lookForChanges(), и она принимает и возвращает void.Этот метод вызывается планировщиком Spring (@Scheduled) и управляет всем процессом: он извлекает данные из БД, извлекает данные из веб-службы, сравнивает их и, если были какие-либо изменения, обновляет базу данных и отправляетJMS сообщение для клиента.Конечно, он не выполняет все эти функции сам по себе, но вызывает соответствующие классы и методы.

Итак, первая проблема, с которой я столкнулся, - это создание модульного теста для метода void.Во всех руководствах всегда протестированные методы принимают параметры и возвращают результат.Я нашел ответ на этот вопрос в этом вопросе .Он говорит, что даже если нет результата для проверки, по крайней мере один может убедиться, что методы внутри тестируемого метода были вызваны и имеют правильный порядок параметров.

Мне вроде понравился этот ответ, но проблемаЯ работаю в TDD, поэтому, в отличие от парня, который задал этот вопрос, я пишу тест перед реализацией тестируемого метода, поэтому я пока не знаю, какие методы и в каком порядке он будет использовать.Я могу догадаться, но я буду уверен в этом только после того, как метод будет уже реализован.

Итак, как я могу проверить метод пустого скелета перед его реализацией?

1 Ответ

0 голосов
/ 03 июня 2018

Итак, первая проблема, с которой я столкнулся, - это создание модульного теста для метода void.

Метод void подразумевает коллабораторов.Вы проверяете это.

Пример.Предположим, нам нужна была задача, которая скопировала бы System.in в System.out.Как бы мы написали автоматизированный тест для этого?

void copy() {
    // Does something clever with System.in and System.out
}

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

void copy() {
    InputStream in = System.in;
    PrintStream out = System.out;
    // Does something clever with `in` and `out`
}

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

void copy() {
    InputStream in = System.in;
    PrintStream out = System.out;
    copy(in, out);
}

void copy(InputStream in, PrintStream out) {
    // Does something clever with `in` and `out`
}

Последний из них - это API, который мы можем протестировать - мы настраиваем соавторов, передаем их в тестируемую системуи проверьте изменения позже.

На данный момент у нас нет теста для void copy(), но это нормально, так как код «настолько прост, что явно нет недостатков».

Обратите внимание на то, что с точки зрения теста между этими схемами нет большой разницы

{
    Task task = new Task();
    task.copy(in, out);
}

{
    Task task = new Task(in, out);
    task.copy();
}

{
    Task task = Task.createTask();
    task.copy(in, out)
}

{
    Task task = Task.createTask(in, out);
    task.copy();
}

Можно подумать об этом так: мы не пишемСначала API, мы сначала пишем test .

// Arrange the test context to be in the correct initial state
// ???
// Verify that the test context arrived in final state consistent with the specification.

То есть, прежде чем начать думать об API, сначала нужно разобраться, как вы собираетесь оценить результат.

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

Хорошо, теперь я могу передать params методу для его тестирования, но что я могу проверить?

Вы проверяете, что он должен делать.

Попробуйте этот мысленный эксперимент - предположим, что вы и я спаривались, и вы предложили этот интерфейс

interface Task {
    void lookForChanges();
}

и затем, после некоторого тщательного размышления, я реализовал это:

class NoOpTask implements Task {
    @Override
    void lookForChanges() {}
}

Как бы вы продемонстрировали, что моя реализация не удовлетворяет требованиям?

То, что вы написали в вопросе, было «оно обновляет базу данных и отправляет JMS-сообщение клиенту», поэтому необходимо рассмотреть два утверждения: обновилась ли база данных и было ли отправлено сообщение JMS?

Все выглядит примерно так

Given:
    A database with data `A`
    A webservice with data `B`
    A JMS client with no messages

When:
    The task is connected to this database, webservice, and JMS client
    and the task is run

Then:
    The database is updated with data `B`
    The JMS client has a message.

Похоже, то, что вы предлагаете, является сквозным тестом.

Этовыглядит как один.Но если вы используете удвоение теста для этих сотрудников, а не живых систем, тогда ваш тест выполняется в изолированной и детерминированной оболочке.

Это, вероятно, общительный тест - тест не знает или не заботится о реализацииподробности тестируемой системы в предложении when.Я не утверждаю, что SUT является единым целым и единым целым.

Сначала я должен увидеть реализацию foo.Я ошибся?

Да - вам нужно понимать спецификацию foo, а не реализацию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...