2013-02-22 87 views
1

我已經實現了一個使用下面的C函數的門面模式,我想正確地測試它。是否有可能在運行時交換C函數實現?

我真的不能控制這些C函數。它們在頭文件中實現。現在我#ifdef在生產中使用真正的頭文件,在測試中使用我的模擬頭文件。 C中有沒有辦法通過覆蓋C函數地址或其他東西來在運行時交換C函數?我想擺脫我的代碼中的#ifdef。

+0

看看微軟走彎路。你可以勾住它們大概 – 2013-02-22 09:48:37

+7

看看函數指針。 – 2013-02-22 09:50:03

+0

#ifdef有什麼問題? – 2013-02-22 09:53:45

回答

1

要擴展巴特的答案,請考慮以下簡單的例子。

#include <stdio.h> 
#include <stdlib.h> 

int (*functionPtr)(const char *format, ...); 

int myPrintf(const char *fmt, ...) 
{ 
    char *tmpFmt = strdup(fmt); 
    int i; 
    for (i=0; i<strlen(tmpFmt); i++) 
     tmpFmt[i] = toupper(tmpFmt[i]); 

// notice - we only print an upper case version of the format 
// we totally disregard all but the first parameter to the function 
    printf(tmpFmt); 

    free(tmpFmt); 
} 

int main() 
{ 

    functionPtr = printf; 
    functionPtr("Hello world! - %d\n", 2013); 

    functionPtr = myPrintf; 
    functionPtr("Hello world! - %d\n", 2013); 

    return 0; 
} 

輸出

Hello World! - 2013 
HELLO WORLD! - %D 
1

奇怪的是,你甚至需要一個IFDEF選擇的標題。代碼測試和你的模擬應該有完全相同的功能簽名爲了成爲模塊的測試正確的模擬。然後,在生產編譯和測試編譯之間唯一的變化就是你給鏈接器的文件是哪個文件。

0

我不認爲在運行時覆蓋函數不是一個好主意。首先,可執行段可以設置爲只讀,即使它不是你可能最終踩到另一個函數的代碼,如果你的程序集太大。

我認爲你應該爲你想使用的一個和另一組實現創建一個類似於函數指針集合的東西。每次你想調用一個函數時,你都會從選定的函數指針集合中調用。完成這些之後,您可能還會有代理函數(僅從所選集合中調用)來隱藏函數指針語法。

1

有可能使用Typemock Isolator ++而不會創建不必要的新的間接層級。它可以在測試中完成,而不會改變您的生產代碼。請看下面的例子:

你在你的代碼中的Sum函數:

int Sum(int a, int b) 
{ 
    return a+b; 
} 

而且要與西格瑪來取代它爲您的測試:

int Sigma(int a, int b) 
{ 
    int sum = 0; 

    for(; 0<a ; a--) 
    { 
     sum += b; 
    } 

    return sum; 
} 

在您的測試,模擬求和使用前:

WHEN_CALLED:調用你想僞造的方法。

ANY_VAL:指定模擬將應用的參數值。在這種情況下是2個整數。

* DoStaticOrGlobalInstead:您希望用於Sum的替代行爲。 在這個例子中,我們將其稱爲Sigma。

TEST_CLASS(C_Function_Tests) 
{ 
public: 

TEST_METHOD(Exchange_a_C_function_implementation_at_run_time_is_Possible) 
{ 
    void* context = NULL; //since Sum global it has no context 
    WHEN_CALLED(Sum (ANY_VAL(int), ANY_VAL(int))).DoStaticOrGlobalInstead(Sigma, context); 

    Assert::AreEqual(2, Sum(1,2)); 
} 
}; 

* DoStaticOrGlobalInstead 它可以設置其他類型的行爲,而不是調用的替代方法。您可以拋出一個異常,返回值,忽略方法等等

例如:

TEST_METHOD(Alter_C_Function_Return_Value) 
{ 
    WHEN_CALLED(Sum (ANY_VAL(int), ANY_VAL(int))).Return(10); 
    Assert::AreEqual(10, Sum(1,2)); 
} 
相關問題