[英]How do you mock and test the same function in C/C++ with FFF and Google Test?
我正在探索 TDD(測試驅動開發)來測試我在 C 和 C++ 中編寫的代碼。 我選擇使用 Google Test 作為單元測試框架。 我選擇使用 FFF 作為 mocking 框架。
我寫了一些測試並運行它們,效果很好。 但是我遇到了一個問題,我無法在網上找到任何參考資料,我希望社區可以幫助我(這也可以幫助其他人)。
我遇到的問題是我想為 function A1 編寫一個測試(參見下面的場景 1)。 由於它調用了另外三個函數(B1、B2 和 B3)並且它們有很多依賴關系,因此我決定模擬它們,以便測試可能影響 function A1 行為的各種場景。 為了使模擬工作並避免 linker 錯誤(例如“B1 的多個定義”),我需要在函數(B1、B2 和 B3)之前編寫“屬性((弱))”。 到目前為止,一切都很好。 一切都很好。
現在,考慮下面的場景 2。 在這種情況下,我想在單獨的測試中測試 function B1。 同樣,我也會模擬它調用的函數(C1、C2、C3)。 但是,問題是我不能調用“真實的”B1 function,因為如果我這樣做,我將得到我之前在 A1 測試中定義的模擬 function(場景 94F41A 下定義) ZC1C425268E68385D1AB5074C1
那么在這種情況下我該怎么辦呢? 謝謝。
在 James Grenning 所著的《嵌入式 C 的測試驅動開發》一書中,我做了一些更多的挖掘和發掘,至少有兩個解決這個問題的方法。
此選項的一般摘要:
總體而言,這似乎不太直觀,難以實現和遵循,並且需要一些學習曲線。 但是,好處是您不需要更改生產代碼中的任何內容,這非常重要。
在這種情況下,您需要使用 makefile 來執行以下步驟:
將您的生產代碼構建到庫中
請務必將您的測試分成不同的文件,以便需要使用某個 function 作為模擬的測試與需要使用相同 function 的原始實現的測試分開。
使用 make 文件,您將需要對部分代碼進行微構建,最后將它們組合在一起。 例如,對於特定的 function,您希望在不同的測試中模擬和使用原始實現,這些測試被分隔在兩個文件中(test1.cpp 包含 func A1 的模擬實現,test2.cpp 包含function A1) 你會做:
現在這三個步驟只是一個高級解釋。 我知道這並不理想,但仍然值得。 我承認我不是自己做的,但我確實讀過 James Grenning 的書,如果您願意,他會在他的書中的附錄 1(標題為開發系統測試環境)中更詳細地解釋它,您可能會看到 makefile 結構他在這里使用了他的書代碼示例: https://pragprog.com/titles/jgade/test-driven-development-for-embedded-c/
此選項的一般摘要:
這更加直觀且易於實現。 但是,缺點是它需要對您的生產代碼進行細微的更改,在該代碼中聲明和定義了 function。
假設您要模擬一個名為 A1 的 function 文件 Production.c 文件中定義為:
//Production.c
int A1(void)
{
... original implementation written here
}
在 Production.h 中聲明為:
//Production.h
int A1(void);
因此您可以通過這種方式更改 function 聲明和定義:
//Production.c
int A1_original(void)
{
... original implementation written here
}
int (*A1)(void) = A1_original;
在 Production.h 中聲明為:
//Production.h
extern int (*A1)(void);
#ifdef TDD_ENABLED // use ifdef with TDD_ENABLED which is defined only in unit test project. This is because you want to declare the original implementation function as a public function so that you can freely assign it to the function pointer A1 in the test files.
int A1_original(void);
#endif
現在,對於要使用原始 function 實現的每個測試,只需按照更改前的相同方式調用它:
A1();
如您所見,這意味着,在整個生產代碼中,您無需更改調用 function 的方式。 這也適用於您的測試文件。
現在,如果您想為此 function 使用模擬,您只需執行以下操作:
//Test1.cpp
int Fake_A1(void)
{
... fake function implementation
}
TEST(test_group_name,test_name)
{
int (*temp_holder)(void) = A1; // hold the original pointer in a temp pointer
A1 = Fake_A1; // assign A1 to call the mock function
... run all the test here
A1 = temp_holder; // assign A1 to call the original function back again so that the mock function is used only in the scope of this test
}
理想情況下,如果您打算進行多個此類測試,您可以在使用帶有Setup()
和 Teardown( Teardown()
的 class 並使用如下測試夾具 ( TEST_F
) 時對模擬進行分配並重新分配給原始 function:
//Test1.cpp
class A1_Func_Test : public ::testing::Test
{
protected:
int (*temp_holder)(void) = A1; // hold the original pointer in a temp pointer
virtual void SetUp()
{
A1 = Fake_A1; // assign A1 to call the mock function
}
virtual void TearDown()
{
A1 = temp_holder; // assign A1 to call the original function back again so that the mock function exists only in the scope of this test
}
};
TEST_F(A1_Func_Test , Test1_A1)
{
write tests here...
}
TEST_F(A1_Func_Test , Test2_A1)
{
write tests here...
}
按照上面編寫的說明進行操作后,應對您的生產代碼文件(Production.c 和 Production.h)進行相同的更改。 但是,對於您的單元測試文件,您只需執行以下操作,以防您想模擬 function (如果您想在沒有 mocking 的情況下測試 function )然后定期調用它:
//Test1.cpp
//Using FFF Mocking framework:
DEFINE_FFF_GLOBALS;
FAKE_VALUE_FUNC(int, A1_mock);
int A1_custom(void)
{
write code here for mock function implementation...
}
TEST(test_group_name,test_name)
{
int (*temp_holder)(void) = A1; // hold the original pointer in a temp pointer
// setting customized mock function for this test
A1_mock_fake.custom_fake = A1_custom;
A1 = A1_mock;
// simple example of a test using the the FFF framework:
int x;
x = A1();
ASSERT_EQ(A1_mock_fake.call_count, 1);
// assign A1 to call the original function back again so that the mock function exists only in the scope of this test
A1 = temp_holder;
RESET_FAKE(A1_mock); // reset all parameters of the mock function used so when used in a subsequent test we will start "clean"
}
我相信這回答了關於如何 go 的問題並按照我的要求進行操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.