2011-12-06 138 views
6

我喜歡GNU鏈接器的功能來包裝很多功能。我通常使用它模擬例如像rand()這樣的非確定性函數調用。看看下面的例子,我想編寫giveMeANumber單元測試:用GNU鏈接器包裝C++函數

//number.cpp 
int giveMeANumber() { 
    return rand() % 6 + 1; 
} 

我可以換調用蘭德與GNU鏈接功能包裝是這樣的:

//test.cpp 
extern "C" int __wrap_rand(void) { 
return 4; 
} 

void unitTest() { 
    assert giveMeANumber() == 5; 
} 

$ g++ test.cpp -o test number.o -Xlinker --wrap=rand 

有什麼辦法使用正常的C++函數做同樣的事情?以下是行不通的,我猜這是因爲名字混亂。但即使當我嘗試使用損壞的名稱,它也不起作用。

//number.cpp 
int foo() { 
    //some complex calculations I would like to mock 
} 
int giveMeANumber() { 
    return foo() % 6 + 1; 
} 

//test.cpp 
extern "C" int __wrap_foo(void) { 
return 4; 
} 

$ g++ test.cpp -o test number.o -Xlinker --wrap=foo 

任何想法?

+0

實際上,rand是一個確定性函數。它返回一個僞隨機數字序列。調用rand將返回與srand一起使用的任何給定種子的相同數字序列。 – TJD

+1

好的,布拉沃,這是真的。但爲了保持這個例子簡短易讀,我沒有使用種子。 – Mike

+0

您需要將'__wrap_foo'重命名爲'getRandomNumber'。 (http://xkcd.com/221/) –

回答

8

你需要或者也extern "C"要換行(如果可能的話),或者你需要用錯位名稱的功能,例如,__wrap__Z3foov再通--wrap=_Z3foov給連接器。

正確獲取下劃線有點棘手。這適用於我:

$ cat x.cc 
#include <iostream> 
using namespace std; 

int giveMeANumber(); 

int main() { 
    cerr << giveMeANumber() << endl; 
    return 0; 
} 

$ cat y.cc 
int giveMeANumber() { 
    return 0; 
} 

extern "C" int __wrap__Z13giveMeANumberv() { 
    return 10; 
} 

$ g++ -c x.cc y.cc && g++ x.o y.o -Wl,--wrap=_Z13giveMeANumberv && ./a.out 
10 
+0

要包裝的C鏈接C++函數不是一個選項,因爲此函數可能被重載,應該仍然可以從其他C++函數調用它。我試圖包裝這個損壞的名字,但它不起作用。我做的是這樣的:'extern「C」int __wrap__Z3foov(void){ \t return 4; } void thisIsATest(){ assert 5 == giveMeANumber(); } '連同鏈接器選項'-Xlinker --wrap = _Z3foov'。不幸的是,真正的'foo'函數仍然被調用。有任何想法嗎? – Mike

+0

我添加了一個例子。花了我一段時間纔得到所有的下劃線。 – smparkes

+0

並感謝您的問題。我甚至不知道 - 包裝。非常好。 – smparkes

1

這似乎是你試圖模擬函數和類進行測試。你有沒有考慮使用Google Mock

+1

使用谷歌模擬不適合我。我只想在GNU鏈接器的幫助下完成此操作。 – Mike