我有一個函數實現了一個狀態機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();
}
正如我之前所說的,這次測試由於「第二次沒有預期的模擬呼叫產生」而失敗。
什麼可能是一個正確的策略? - >如果每個狀態都沒有測試用例,也只有一個測試用例,哪一個?因此,有沒有關於如何實現上述狀態機的測試代碼的建議?
有人可以改進這個測試代碼嗎?
評論與您的問題無關,但從代碼混合語言不是一個好主意,在可讀性方面。你應該選擇一個,而英語通常是最好的候選人。 – Tim
設計有限狀態機的行業標準方法是將枚舉和函數指針跳轉表一起使用。 [實施例](http://electronics.stackexchange.com/questions/95569/best-practice-to-keep-main-in-embedded-systems/96415#96415)。在調用者中集中所有錯誤檢查也是一個好主意,並且如果可能的話,集中化下一個狀態決策。當你將核心功能理清後,你可以擔心TDD絨毛。 – Lundin
@Lundin當你說「集中調用者的所有錯誤檢查」時,你是在談論測試代碼還是狀態機代碼? 「集中化下一個州的決定」是什麼意思? –