1

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

正如我之前所说,由于“产生了第二个未预期的模拟呼叫”,此测试失败。

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

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

4

1 回答 1

0

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

我相信您正在使用 cpputest 并且我认为您不能在单个函数调用中调用两次模拟,如果我错了,有人可以很高兴地纠正我。

于 2017-07-04T08:18:12.457 回答