2017-03-07 46 views
0

我有一個函數實現了一個狀態機test_hw(),即e。第一個狀態是空閒的,它沒有調用任何內部的模擬函數。但這臺機器還有6個州。這個想法是機器從第一個狀態到最後一個順序,當然還有特定條件,定時器結果條件發生。 在測試中,我只有一個模擬函數返回一個時間值。但是,必須在每個狀態下調用該函數作爲返回下一個狀態值的條件的一部分。它也會在某些州內實施。如何使用模擬的定時器函數對C中的狀態機進行單元測試?

首先,我試圖測試每個狀態作爲測試用例。運行後,測試發現太多失敗。我開始認爲測試狀態機將是一個特殊的測試用例。我正在關注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(); 
} 

正如我之前所說的,這次測試由於「第二次沒有預期的模擬呼叫產生」而失敗。

什麼可能是一個正確的策略? - >如果每個狀態都沒有測試用例,也只有一個測試用例,哪一個?因此,有沒有關於如何實現上述狀態機的測試代碼的建議?

有人可以改進這個測試代碼嗎?

+0

評論與您的​​問題無關,但從代碼混合語言不是一個好主意,在可讀性方面。你應該選擇一個,而英語通常是最好的候選人。 – Tim

+2

設計有限狀態機的行業標準方法是將枚舉和函數指針跳轉表一起使用。 [實施例](http://electronics.stackexchange.com/questions/95569/best-practice-to-keep-main-in-embedded-systems/96415#96415)。在調用者中集中所有錯誤檢查也是一個好主意,並且如果可能的話,集中化下一個狀態決策。當你將核心功能理清後,你可以擔心TDD絨毛。 – Lundin

+0

@Lundin當你說「集中調用者的所有錯誤檢查」時,你是在談論測試代碼還是狀態機代碼? 「集中化下一個州的決定」是什麼意思? –

回答

0

如果我正確理解你的代碼,一旦FLAG_busy不是1,那麼CaptureTimer()函數至少被調用一次,剩餘時間會被調用兩次。剛進行第一次測試時,狀態爲FMINUS_DONE,在下一個週期中該狀態會調用CaptureTimer()兩次,這就是您出錯的原因。

我相信你正在使用cpputest,我不認爲你可以在一個函數調用中調用兩次模擬,如果我錯了,有人可以很樂意糾正我。

相關問題