我有一个实现状态机的函数,test_hw(),即。第一个状态是空闲的,它内部没有调用任何模拟函数。但是这台机器还有6个状态。这个想法是机器依次从第一个状态到最后一个状态,当特定条件,计时器结果条件发生时。在测试中,我只有一个返回时间值的模拟函数。但是这个函数必须作为条件的一部分在每个状态被调用以返回下一个状态值。它也将在某些状态实现中被调用。
首先,我尝试将每个状态作为测试用例进行测试。运行它后,测试发现太多失败。我开始认为测试状态机将是一个特殊的测试用例。我正在关注一本 TDD 书,但它没有谈论测试机器状态。
我尝试的第二件事是将所有 test_hw 机器作为唯一的测试用例进行测试。但是它再次失败了,因为测试从源代码中拦截了超过 6 个调用,而测试只有 6 个(测试代码中每个状态对这个模拟函数的一个调用)。我不明白为什么源代码(生产代码)每个状态都调用它不止一次。但这就是发生的事情。我想这不是对状态机进行单元测试的正确策略。
我将与您分享一个基于我的简化状态机:
eError TestHW()
{
static unsigned char last_state = FMINUS_DONE; //IDLE state
......... //more needed var declaration
if (FLAG_busy==OFF)
{
if (last_state==FMINUS_DONE) /*IDLE */
{
...... //some assignations
timerfcentral=CaptureTimer(); //timer function to be mocked in test mode
last_state= FCENTRAL_COUNT;
}
if ((CaptureTimer()-timerfcentral>=STABLISH_TIME) && (last_state==FCENTRAL_COUNT)) //timer function call to be mocked in test mode
{ //next state
last_state =FCENTRAL_DONE;
......//some assignments
}
else if (last_state ==FCENTRAL_DONE)
{ //next state
timerfplus=CaptureTimer(); //timer function to be mocked in test mode
last_state= FPLUS_COUNT;
.....//some assignments
}
else if ((last_state ==FPLUS_COUNT) && (CaptureTimer()-timerfminus>=STABLISH_TIME)) //timer function to be mocked in test mode
{
.....//some assignments
last_state = FMINUS_DONE;
}
return last_state;
}
else //FLAG_busy=1
{
last_state= FMINUS_DONE; //machine state loop is closed
return last_state; /* busy system */
}
}
测试代码:
TEST(TestHW,TestHW_main)
{
unsigned char error_val;
FLAG_busy =1;
error_val=TestHW();
CHECK_EQUAL(error_val,FMINUS_DONE); //check busy state
mock().enable();
FLAG_busy =0;
mock().expectOneCall("CaptureTimer").andReturnValue(1000);
error_val=TestHW();
CHECK_EQUAL(error_val,FCENTRAL_COUNT) /*check state idle*/
mock().expectOneCall("CapturaTimer").andReturnValue(15000);
error_val=TestHW();
CHECK_EQUAL(error_val,FCENTRAL_DONE);//check first state
mock().expectOneCall("CaptureTimer").andReturnValue(15000);
error_val=TestHW();
CHECK_EQUAL(error_val,FPLUS_COUNT);//check second state
mock().expectOneCall("CaptureTimer").andReturnValue(30000);
error_val=TestHW();
CHECK_EQUAL(error_val,FMINUS_DONE);//check last state
mock().disable();
}
Mock.c 文件中的模拟计时器函数实现:
unsigned long CaptureTimer(void)
{
mock().actualCall("CaptureTimer");
return mock().unsignedIntReturnValue();
}
正如我之前所说,由于“产生了第二个未预期的模拟呼叫”,此测试失败。
什么是正确的策略?--> 如果没有每个状态的测试用例,也没有只有一个测试实体,是哪一个?因此,对于上面显示的状态机的测试代码的实现方式有什么建议吗?
有人可以改进这个测试代码吗?