如何使用定时器函数模拟在C中对状态机进行单元测试?

时间:2017-03-07 11:44:50

标签: c unit-testing mocking state-machine cpputest

我有一个实现状态机的函数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();
}

正如我之前所说,此测试由于"第二次没有预期的模拟电话产生"而失败。

什么是正确的策略? - >如果没有每个状态的测试用例,也只有一个测试实体,哪一个?因此,有没有关于为上面显示的状态机实现测试代码的方法的建议?

有人可以改进此测试代码吗?

1 个答案:

答案 0 :(得分:0)

如果我正确理解您的代码,则FLAG_busy不再为1时,CaptureTimer()函数至少调用一次,剩余时间调用两次。在第一次测试之后,状态为FMINUS_DONE,在下一个周期中调用CaptureTimer()两次,这就是您遇到错误的原因。

我相信你正在使用cpputest而且我不认为你可以在一个函数调用中有一个叫两次的模拟,如果我错了,有人可以很乐意纠正我。