是否有可能在运行时交换C函数实现?

问题描述:

我已经实现了一个使用下面的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

要扩展巴特的答案,请考虑以下简单的例子。

#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 

奇怪的是,你甚至需要一个IFDEF选择的标题。代码测试和你的模拟应该有完全相同的功能签名为了成为模块的测试正确的模拟。然后,在生产编译和测试编译之间唯一的变化就是你给链接器的文件是哪个文件。

我不认为在运行时覆盖函数不是一个好主意。首先,可执行段可以设置为只读,即使它不是你可能最终踩到另一个函数的代码,如果你的程序集太大。

我认为你应该为你想使用的一个和另一组实现创建一个类似于函数指针集合的东西。每次你想调用一个函数时,你都会从选定的函数指针集合中调用。完成这些之后,您可能还会有代理函数(仅从所选集合中调用)来隐藏函数指针语法。

有可能使用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)); 
}