c - 在 MSVC (Visual Studio) 中模拟 C 函数

标签 c visual-studio unit-testing mocking cmock

我正在阅读几篇关于模拟 C 函数的文章(如 CMockCMocka ),但我不确定在此过程中如何将实际函数替换为模拟函数。例如,CMocka 依赖于使用 GNU 编译器的自动包装,它支持像 --wrap 这样的参数将 __wrap 前缀附加到函数调用,或者弱符号 允许您覆盖任何您喜欢的符号。

但是对于几乎所有其他框架,您如何在 Visual Studio 中执行此操作?

例如,CMock has an example类似于此(这里简化了很多):

// myfunc.c
#include <parsestuff.h>

// this is the function we would like to test
int MyFunc(char* Command)
{
    // this is the call to the function we will mock
    return ParseStuff(Command);
}

还有实际的实现,包含链接器在实际应用中应该找到的实际功能:

// parsestuff.c

int ParseStuff(char* cmd)
{
    // do some actual work
    return 42;
}

现在,在测试期间,Ruby 脚本会创建如下模拟函数:

// MockParseStuff.c (auto created by cmock)

int ParseStuff(char* Cmd);
void ParseStuff_ExpectAndReturn(char* Cmd, int toReturn);
  1. 但是如果VS工程中已经包含了parsestuff.c,那么myfunc.c的调用怎么可能在MockParseStuff中结束呢? .c?

  2. 这是否意味着我不能将 parsestuff.c 包含在单元测试项目中?但如果是这种情况,那么也不可能在任何测试中模拟 myfunc.c 中的 MyFunc,因为我已经必须将文件包含在其中为了测试它?

(更新) 我也知道我可以包含 .c 文件而不是 .h 文件,然后做一些用于替换原始调用的预处理器内容,例如:

// replace ParseStuff with ParseStuff_wrap
#define ParseStuff ParseStuff_wrap
// include the source instead of the header
#include <myfunc.c>
#undef ParseStuff

int ParseStuff_wrap(char* cmd) 
{
    // this will get called from MyFunc,
    // which is now statically included
}

但这似乎有很多管道,我什至没有看到任何地方提到它。

最佳答案

这是一个简单而简短的 hippomocks 解决方案:

我用

创建了一个空的 Win32 控制台应用程序
  • main.cpp
  • myfunc.c + myfunc.h
  • parsestuff.c, parsestuff.h

并添加了您示例中的代码。

借助 hippomocks,您可以模拟每个 C 函数。这是我的 main.cpp 的样子:

#include "stdafx.h"
#include "myfunc.h"
#include "hippomocks.h"


extern "C" int ParseStuff(char* cmd);

int _tmain(int argc, _TCHAR* argv[])
{
    MockRepository mocks;

    mocks.ExpectCallFunc(ParseStuff).Return(4711);

    char buf[10] = "";

    int result = MyFunc(buf);

    return result; //assert result is 4711
}

HippoMocks 是一个免费、简单且非常强大的单头框架,可以在 GitHub 上下载。

希望我已经赢得赏金:)

更新,它是如何工作的:

  1. HippoMocks 获取指向 ParseStuff 的函数指针
  2. HippoMocks 构建一个替换函数指针,指向具有相同签名和自己实现的模板函数。
  3. Hippomocks 修补内存中函数调用序言中的 jmp 操作码,使其指向被替换的函数。
  4. 替换和内存补丁在调用后或在析构函数中释放。

这是它在我的机器上的样子:

@ILT+3080(_ParseStuff):
00D21C0D  jmp HippoMocks::mockFuncs<char,int>::static_expectation1<0,char *> (0D21DB1h)  

如果您在内存窗口中查看内存地址 00D21C0D(可能因运行而异),您会看到它在调用 ExpectCallFunc 后得到了修补。

关于c - 在 MSVC (Visual Studio) 中模拟 C 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38615983/

相关文章:

c - 不理解这个结构类型定义

c - 将文件中的数据读入 C 中的数组错误

javascript - Visual Studio 2010 文件打开 - 说它已经打开!

c# - C#单元测试。并非所有路径都返回值

C select() writefds

c - 带指针的双向链表段错误

c++ - 如何通过 C++ 可执行文件中的 list 启用 "Long Path Aware"行为?

c# - Visual Studio Web 测试 api 请求失败 'Invalid HTTP header characters'

java - 如何在 RxJava 2 中使用 TestObserver 对对象列表进行单元测试?

unit-testing - 我如何测试代码是否真的启动了一个 go 例程?