嘲讽C函数在MSVC(Visual Studio中) [英] Mocking C functions in MSVC (Visual Studio)

查看:193
本文介绍了嘲讽C函数在MSVC(Visual Studio中)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读的嘲讽C函数(如 CMock ,或的 CMocka ),但我不知道实际的功能是如何与在这个过程中嘲笑的功能所取代。例如,CMocka依赖于使用GNU编译器,它支持像参数自动包装 - 包装追加 __包装 preFIX调用函数,或弱符号的,让你可以重写你喜欢的任何符号。

但你如何做到这一点在Visual Studio中,为pretty很多其他框架?

例如, CMock有一个例子的类似这样的(这里简化了很多):

  // myfunc.c
#包括LT&;&parsestuff.h GT;//这是函数,我们想测试
INT MYFUNC(字符*命令)
{
    //这是调用我们会嘲笑功能
    返回ParseStuff(命令);
}

还有实际执行,它包含了实际功能连接器应在实际应用中发现:

  // parsestuff.cINT ParseStuff(字符* CMD)
{
    //做一些实际的工作
    返回42;
}

现在,在测试Ruby脚本创建像模拟功能:

  // MockParseStuff.c(由cmock创建自动)INT ParseStuff(字符* CMD);
无效ParseStuff_ExpectAndReturn(字符* Cmd的,诠释toReturn);


  1. 但是,如果VS项目已经包括 parsestuff.c ,怎么才有可能从呼叫 myfunc.c MockParseStuff.c


  2. 这是否意味着我不能有 parsestuff.c 包含在单元测试项目?但是,如果是这样的话,那么它也不可能嘲笑,例如, MYFUNC myfunc.c 中的任何测试中,因为我已经有包含的文件是为了测试它?


(更新)我也知道,我可以包括 .C 文件,而不是 .H 文件,然后做一些preprocessor的东西来代替原来的呼叫,如:

  //使用ParseStuff_wrap取代ParseStuff
#定义ParseStuff ParseStuff_wrap
//包括源,而不是头
#包括LT&;&myfunc.c GT;
和#undef ParseStuffINT ParseStuff_wrap(字符* CMD)
{
    //这会得到MYFUNC叫,
    //这是目前静态包含
}

不过这好像很多管道,我甚至不看它的任何地方提及。


解决方案

下面是用hippomocks一个简单的和短期的解决方案:

我创建了一个空的Win32控制台应用程序


  • 的main.cpp

  • myfunc.c + myfunc.h

  • parsestuff.c,parsestuff.h

和您的例子增加了code。

随着hippomocks的帮助下,你可以模拟所有的C函数。这里是我的main.cpp的样子:

 的#includestdafx.h中
#包括myfunc.h
#包括hippomocks.h
为externCINT ParseStuff(字符* CMD);INT _tmain(INT ARGC,_TCHAR *的argv [])
{
    MockRepository嘲笑;    mocks.ExpectCallFunc(ParseStuff).Return(4711);    炭的buf [10] =;    INT结果= MYFUNC(BUF);    返回结果; //断言结果是4711
}

HippoMocks是一个免费,简单,很强大的一个头框架里,可以在GitHub上下载。

希望我已经赢得了奖金:)

UPDATE,它是如何工作:


  1. HippoMocks得到FUNC指针ParseStuff

  2. HippoMocks建立一个替代FUNC指向与相同的签名和自己的实现模板功能。

  3. Hippomocks补丁从内存中的函数调用序幕JMP运算code,使其指向替换功能。

  4. 替换和内存补丁被调用后或析构函数释放。

下面是它的外观像我的机器上:

  @ ILT + 3080(_ParseStuff):
00D21C0D JMP HippoMocks :: mockFuncs< CHAR,INT和GT; :: static_expectation1℃下,字符*> (0D21DB1h)

如果你看的内存地址00D21C0D在内存窗口(可以从运行的不同运行),你会看到,它被ExpectCallFunc的电话后打补丁。

I am reading several articles on mocking C functions (like CMock, or CMocka), but I am not sure how the actual functions are replaced with mocked functions in this process. For example, CMocka relies on automatic wrapping using a GNU compiler, which supports parameters like --wrap to append the __wrap prefix to function calls, or weak symbols which allow you to override any symbol you like.

But how do you do this in Visual Studio, for pretty much all other frameworks?

For example, CMock has an example similar to this (simplified a lot here):

// 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);
}

There is also the actual implementation, which contains the actual function the linker should find in the actual application:

// parsestuff.c

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

Now, during testing the Ruby script creates mock functions like:

// MockParseStuff.c (auto created by cmock)

int ParseStuff(char* Cmd);
void ParseStuff_ExpectAndReturn(char* Cmd, int toReturn);

  1. But if the VS project already includes parsestuff.c, how will it be possible that the call from myfunc.c ends up in MockParseStuff.c?

  2. Does this mean I cannot have parsestuff.c included in the unit testing project? But if this is the case, then it's also impossible to mock, for example, MyFunc from myfunc.c in any tests, since I already had to include the file it in order to test it?

(Update) I am also aware that I can include the .c file instead of the .h file, and then do some preprocessor stuff to replace the original call, like:

// 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
}

but this seems like a lot of plumbing, and I don't even see it mentioned anywhere.

解决方案

Here's a simple and short solution with hippomocks:

I created an empty Win32 console application with

  • main.cpp
  • myfunc.c + myfunc.h
  • parsestuff.c, parsestuff.h

and added the code from your example.

With help of hippomocks, you can mock every C-Function. Here's how my main.cpp looks like:

#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 is a free, simple and very powerful one-header framework and can be downloaded on GitHub.

Hope I've earned the bounty :)

UPDATE, How it works:

  1. HippoMocks gets the func pointer to ParseStuff
  2. HippoMocks builds a replacement func pointer to a template function with same signature and own implementation.
  3. Hippomocks patches the jmp opcode from the function call prologue in memory, so that it points to the replaced function.
  4. Replacement and memory patch are released after call or in destructor.

Here's how it looks like on my machine:

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

If you watch the memory address 00D21C0D (may differ from run to run) in memory window, you will see, that it gets patched after the call of ExpectCallFunc.

这篇关于嘲讽C函数在MSVC(Visual Studio中)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆