在检查断言时,对包含无限循环的函数执行单元测试会带来问题。这是因为测试用例需要被测试的函数退出才能执行断言验证。但是,在某些情况下,用户可以为包含无限循环的函数实现测试用例。这是通过使用允许无限循环代码执行的条件中断的特殊宏和函数来实现的:
名称 | 详情 |
---|---|
CPPTEST_REGISTER_JMP (表达式) | 使用 setjmp 或 sigsetjmp 设置内部跳转缓冲区并评估传递的表达式。可以使用 CPPTEST_JMP API 调用跳转到缓冲区。 这个宏通常在测试用例中使用,它包装对测试函数的调用(见下面的例子)。 |
CPPTEST_JMP (value) | 执行 longjmp 调用(使用 longjmp 或 siglongjmp),将执行状态恢复到最近 此宏通常用于桩函数主体内部。它接受一个整数参数,该参数将通过 cpptestGetJmpReturn 函数在测试用例中返回。整数参数可用于验证执行跳转的正确性(参见下面的示例)。 |
int CDECL_CALL cpptestGetJmpReturn(); | 返回最近一次 CPPTEST_JMP 调用的返回值,即 longjmp/siglongjmp 的参数,它是 setmp/sigsetjmp 的返回值。 |
这些宏旨在结合使用,旨在为用户提供中断测试代码执行的能力(例如在桩函数主体内)并返回到测试用例以执行断言检查。它们的功能类似于标准 setjmp.h 头文件中声明的 setjmp 和 longjmp 调用。
此功能可用于测试包含无限循环的典型事件处理嵌入式函数。中断测试代码的执行是通过调用 CPPTEST_JMP 来完成的。向 CPPTEST_JMP 注入调用的推荐技术是通过桩函数主体。
以下示例说明了这些宏和函数的最常见用法:
/* Function to be tested */ void signalData(void) { while(1) { // Get the returning frequency from the frequency sensor. if (scanFrequencySensor (returningFrequency) == FAILURE) { // If sensor has an error, don't give semaphore, // report error, call recovery and retry log_error("The sensor has encountered an error, retrying...\n"); recover(); } else { semGive(dataSemId); taskDelay(DELAY_TICKS); } } } /* Test case */ /* CPPTEST_TEST_CASE_BEGIN test_signalData */ /* CPPTEST_TEST_CASE_CONTEXT void signalData(void) */ void TestSuite_main_c_883563c3_test_signalData() { /* Pre-condition initialization */ /* Initializing global variable returningFrequency */ returningFrequency = 0; /* Tested function call */ CPPTEST_REGISTER_JMP(signalData()) /* Post-condition check */ CPPTEST_POST_CONDITION_INTEGER("cpptestGetJmpReturn()=", ( cpptestGetJmpReturn() )); CPPTEST_ASSERT_INTEGER_EQUAL(0, ( returningFrequency )); } /* CPPTEST_TEST_CASE_END test_signalData */ /* Stub */ /** User stub definition for function: int scanFrequencySensor(int) */ EXTERN_C_LINKAGE int scanFrequencySensor (int returningValue) ; EXTERN_C_LINKAGE int CppTest_Stub_scanFrequencySensor (int returningValue) { static unsigned int counter = 0; unsigned int ret = 0; counter++; //Simulate failure every 5 scans of the sensor if (counter == 5) { CPPTEST_REPORT("Simulating sensor scan failure") ret = FAILURE; } else if (counter == 10) { CPPTEST_REPORT("Testing accomplished - going back to test case for assertions check") CPPTEST_JMP(counter) } else { ret = scanFrequencySensor(returningValue); } return ret; }
当 C++test 执行 TestSuite_main_c_883563c3_test_signalData 测试用例时,它会在调用被测试函数之前保存跳转缓冲区。当执行测试代码时,它会从 CppTest_Stub_scanFrequencySensor 桩函数主体调用 CPPTEST_JMP,它将代码执行转移回测试用例以执行断言检查。