Должны ли мы изменить сигнатуру функции для модульного тестирования? - PullRequest
0 голосов
/ 30 мая 2019

Предположим, у нас есть функция add(), как показано ниже:

void add(int a, int b) {
    int sum=a+b;
    cout<<sum;
    sendSumToStorage(sum);
}

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

В целях модульного тестирования оно действительно (с точки зрения дизайна)) если мы изменим сигнатуру функции, чтобы она возвращала sum?Тогда у нас может быть тест вроде:

bool checkAdd() {
    int res=add(3, 4);
    if(res==7) return true;
    else return false;
}

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

Ответы [ 3 ]

3 голосов
/ 30 мая 2019

Функция, подобная той, что в вашем примере, считается очень плохой практикой.

Почему я так говорю?

Ну, у вас есть метод с именем add , который добавляет два числа И , что-то еще.По сути, ваш метод делает не одну вещь, а две, что нарушает принцип единой ответственности.

Это усложняет тестирование, поскольку вы не можете протестировать только метод add в отдельности.

Таким образом, вы должны разделить это на два метода с хорошими именами, которые отражают то, что они делают, и протестировать их по отдельности.

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

0 голосов
/ 30 мая 2019

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

В вашем случае код сложно протестировать, поскольку он сочетает в себе вычисления (сложение) с взаимодействиями с зависимыми компонентами (вывод и хранение данных). В вашем случае (как указал Андрей) функция также нарушает SRP, но смешивание вычислений и взаимодействий обычно затрудняет тестирование, даже в тех случаях, когда SRP не нарушается.

Насколько я понимаю, вы бы изменили функцию так, чтобы она возвращала вычисленное значение в дополнение к его печати и записи в хранилище. Это позволит вам проверить вычислительную часть функции. Функция тогда, однако, будет проверена только частично. И цель функции будет еще более запутана.

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

0 голосов
/ 30 мая 2019

Игнорирование того факта, что этот пример имеет плохой дизайн.

В подобных случаях, когда вы хотите проверить какое-то внутреннее поведение вместо API, вам лучше попробовать использовать некоторые тестирующие библиотеки, такие как gtest и gmock. Это позволяет вам описать более сложные ожидания, чем просто результат функции.

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

Подробнее здесь: https://github.com/google/googletest/blob/master/googlemock/docs/ForDummies.md

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

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