Тест: что дано, при каком условии, что требуется доказать
После тренинга Кевлина Хенни, я понял, что отсутствие под рукой удобной библиотеки для unit тестирования не является причиной его не использовать. Макрос assert, который есть везде, является достаточным условием для использования тестов.
Например, есть мини-проект в один файл, и не охота тащить Google Test или cmockery. Я обычно делаю что-то такое:
#include <cassert>
void foo(...) {
// something
}
...
#ifdef UNIT_TESTING
void Test_for_a_particular_use_case() {
// Initialization
...
assert(condition_1);
...
assert(condition_N);
}
...
int main(...) {
Test_for_a_particular_use_case();
std::cout << “All tests passed.” << std::endl;
return 0;
}
#else
int main(...) {
// a proper main
}
#endif
Тут, конечно, не так удобно, так как иногда забываешь добавить запуск теста в main(), и вроде как бы все работает, но на самом деле просто тест не запускается.
Но! Все это мелочи, по сравнению с удобством, которое дают тесты.
P.S.
Кстати, заметил за собой интересую привычку. Практически всегда, когда пишу функцию, работающую с файлами, всегда рождаются две, например:
void FunctionDoingSomethingFromStream(std::istream* is) {
...
}
void FunctionDoingSomethingFromFile(const std::string& filename) {
std::ifstream is(filename);
return FunctionDoingSomethingFromStream(&is);
}
Первая функция прекрасно тестируется, так как ей можно подсунуть std::istringstream с тестовыми данными. Вторую же можно практически не тестировать (ну разве что на фазе QA, на реальных файлах, но не в unit-тестах в процессе сборки).
Еще интересный приемчик от Кевлина Хенни. У теста обычно есть объект тестирования (класс или функция), начальное условие (pre-condition) и конечное состояние (post-condition). И данные фазы удобно подчеркнуть в комментариях словами “Given”, “When” и “Then”, например:
void Test_for_a_particular_use_case_to_check() {
// Given:
ClassToTest a;
// When:
a.do_this(...);
a.do_that(...);
a.setup_something(...);
// Then:
assert(condition_1);
...
assert(condition_N);
}
Явное разделение этих фаз провоцирует правильную структуру теста: без циклов и условий, и работа только по одному сценарию (для другого сценария будет другой тест).
■
Disclaimer