Я хочу провести модульное тестирование в программе SystemC. Идея состоит в том, чтобы иметь несколько наборов тестов с несколькими тестами в каждом комплекте. Каждый из тестов потребует сброса платформы SystemC (например, путем вызова sc_simcontext::reset()
), но это на самом деле невозможно из-за некоторой ошибки, которая, по-видимому, не будет исправлена в ближайшее время. Поэтому я решил придумать обходной путь.
Я обнаружил, что если я запускаю каждый тест в отдельном процессе, все работает нормально. Следующий фрагмент кода дает обзор схемы, которую я использовал, чтобы заставить ее работать:
void test1() {
// ...
sc_start();
}
void test2() {
// ...
sc_start();
}
typedef std::function<void()> TestFunction;
void run_test(TestFunction test_function) {
pid_t pid = fork();
switch (pid) {
case -1:
throw std::runtime_error("Error forking process");
case 0:
test_function();
exit(0);
default:
waitpid(pid, nullptr, 0);
break;
}
}
int main() {
run_test(test1);
run_test(test2);
}
Теперь я хочу реализовать такую схему тестирования с помощью Boost Unit Test.
Я изучал внутреннюю часть библиотеки Boost Unit Test и обнаружил, что unit_test_main
Кажется, это функция, которая запускает выполнение всех тестов. Но я не мог придумать ненавязчивый способ взаимодействия с Boost Unit Test для запуска каждого теста в отдельном процессе.
Кто-нибудь знает простое решение для запуска каждого теста в другом процессе?
Я не на 100% удовлетворен решением, которое я предложил, но я все равно опубликую его. Для удобства я инкапсулировал все в пространство имен:
Заголовочный файл:
namespace util {
typedef std::function<void()> TestFunction;
void run_test(TestFunction test_function);
} // namespace util
#define SYSTEMC_TEST_CASE(name) \
void name##_impl(); \
BOOST_AUTO_TEST_CASE(name) { \
util::run_test(name##_impl); \
} \
void name##_impl()
Исходный файл:
namespace util {
void run_test(TestFunction test_function) {
pid_t pid = fork();
switch (pid) {
case -1:
throw std::runtime_error("Error forking process");
case 0:
try { test_function(); }
catch (const std::exception& e) {
std::cout << boost::format("Exception caught: %1%") % e.what() << std::endl;
exit(1);
}
catch (...) { exit(1); }
exit(0);
default:
waitpid(pid, nullptr, 0);
break;
}
}
} // namespace util
Пример использования:
BOOST_AUTO_TEST_SUITE(suite)
SYSTEMC_TEST_CASE(test_case1) {
// ...
}
SYSTEMC_TEST_CASE(test_case2) {
// ...
}
BOOST_AUTO_TEST_SUITE_END()
main.cpp
содержит:
#define BOOST_TEST_MODULE TestModule
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test.hpp>
#include <systemc.h>
boost::unit_test::test_suite* init_unit_test_suite(int, char*[]) {
using namespace ::boost::unit_test;
assign_op(framework::master_test_suite().p_name.value,
BOOST_TEST_STRINGIZE(BOOST_TEST_MODULE).trim("\""), 0);
return 0;
}
int sc_main(int argc, char* argv[]) {
return boost::unit_test::unit_test_main(&init_unit_test, argc, argv);
}
Каждый тестовый пример теперь будет выполняться по другому процессу. Поэтому SystemC запускается несколько раз за одно выполнение без каких-либо проблем.
Единственная реальная проблема этого решения заключается в том, что по какой-то причине невозможно использовать приемник файлов при выводе результатов XML. Но я обнаружил, что все работает нормально, если раковина stderr
и вывод перенаправляется в файл.