Создание модульных тестов из таблицы сценариев, в которой указаны исходные данные и ожидаемые результаты

В настоящее время я пытаюсь сгенерировать некоторое UT пост-кодирование для модуля.
Модуль классифицирует входные данные в БД, если совпадение найдено, возвращается правильное значение.

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

То, что я изначально представлял, было либо макросом, который создает такой шаблон и расширяется до тестов с входными данными и ожидаемым результатом, ИЛИ использует структуру, представляющую таблицу сценариев с некоторой помощью макроса, чтобы обернуть его.
(Я думаю, что шаблон C ++ также подходит здесь).

Тем не менее, я не уверен, что это правильный путь, и хотел бы знать, если кто-нибудь может дать некоторые рекомендации, как справиться с этим.
Существует также вопрос о том, как это соответствует подходу TDD.

Вот идея использования CppUTest:

#define GEN_TEST_MOD_CLASSIFIER(GROUP_NAME, TEST_NAME, PRIORITY, isCOMPRESS, isX, EXPECTING) \
TEST(GROUP_NAME, TEST_NAME) \
{ \
int hit; \
setupDB(PRIORITY, isCOMPRESS, isX); \
hit = func(PRIORITY, isCOMPRESS, isX); \
CHECK_EQUAL(EXPECTING, hit); \
}

Пример использования:

GEN_TEST_MOD_CLASSIFIER(Classifier_Tests, LowPriority_NoCompress_NoX__HIT, PRIO_LOW, NOT_COMPRESS, NO_X, HIT_DB)

Спасибо,
Эди.

1

Решение

Что ж, без внешних инструментов лучше всего использовать макросы. Это потому, что вам нужно иметь TEST(GROUP_NAME, TEST_NAME) для каждого теста.

Это может быть не так. Вам может быть хорошо, если у вас нет отдельного контрольного примера для каждого сценария, или CppUTest может поддерживать программный способ добавления контрольных примеров.
В этом случае вы можете создать метод, который принимает вектор кортежей input-output-testcasename. И будет добавлять тестовые случаи / запускать тесты на каждом кортеже. Макросы не нужны.

Примерно так (псевдокод):

typedef std::tuple<std::string, std::string, PriorityType, CompressType, ExpectedValueType> TestInfo;

void RunTest(const TestInfo& testInfo)
{
// Assuming here you're OK with this kind of test cases separation
std::cout << "Running test" << std::get<0>(testInfo) << ", " << std::get<1>(testInfo) << std::endl;

int hit;
setupDB(std::get<2>(testInfo), std::get<3>(testInfo), isX);
hit = func(std::get<2>(testInfo), std::get<3>(testInfo), isX);
CHECK_EQUAL(std::get<4>, hit);
}

void RunTests(const TestInfo& testInfo)
{
std::for_each(testInfo.begin(), testInfo.end(), RunTest);
}

std::vector<TestInfo> tests = { test1, test2 };
RunTests(tests);

Если это не сработает, макросы на самом деле хороши, и вы также можете использовать табличный подход. Посмотрите на Boost препроцессор (http://www.boost.org/doc/libs/1_54_0/libs/preprocessor/doc/index.html)

Снова псевдокод:

#include <boost\preprocessor\seq.hpp>

#define GENERATE_TEST_CASE(_ignore1_, _ignore2_, _testCaseInfoSequence_) \
TEST(BOOST_PP_SEQ_ELEM(0, testCaseInfoSequence), BOOST_PP_SEQ_ELEM(1, testCaseInfoSequence)) \
{ \
int hit; \
setupDB(BOOST_PP_SEQ_ELEM(2, testCaseInfoSequence), BOOST_PP_SEQ_ELEM(3, testCaseInfoSequence), BOOST_PP_SEQ_ELEM(4, testCaseInfoSequence)); \
hit = func(BOOST_PP_SEQ_ELEM(2, testCaseInfoSequence), BOOST_PP_SEQ_ELEM(3, testCaseInfoSequence), BOOST_PP_SEQ_ELEM(4, testCaseInfoSequence)); \
CHECK_EQUAL(BOOST_PP_SEQ_ELEM(5, testCaseInfoSequence), hit); \
}

#define TESTCASES \
( \
(Group1)(Test1)(prio1)(isCompress1)(isX1)(expectedVal1) \
(Group1)(Test2)(prio2)(isCompress2)(isX2)(expectedVal2) \
)

// This statement will generate all tests cases in defined in TESTCASES sequnce.
BOOST_PP_SEQ_FOREACH(GENERATE_TEST_CASE, _ignore_, TESTCASES);
1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector