我是gmock的新手,所以我想知道如何在单元测试中存根测试函数中调用的简单C函数。
示例:
int func(int a)
{
boolean find;
// Some code
find = func_1();
return find;
}
我搜索了gmock,据我所知,gmock不提供stub简单C函数的功能,因此我想问一下gmock提供mock或stub func_1
的功能吗?
如果没有,我怎么能在不改变源代码的情况下手动在测试代码中存根func_1
呢?我正在使用google测试框架进行单元测试。
谢谢。
7条答案
按热度按时间djp7away1#
这是我对这个问题的另一个答案。在第一个答案之后的两年里,我开始明白GMock只是一个错误的模仿C函数的框架。在你有很多函数要模仿的情况下,我之前发布的答案实在是太麻烦了。原因是GMock使用 Object Seams 来用模仿代码替换生产代码。这依赖于多态类,而C语言中没有。
相反,要模拟C函数,你应该使用 Link Seams,它在链接时用模拟代码替换生产代码。有几个框架可以实现这个目的,但我最喜欢的是 Fake Function Framework(FFF)。看看它,它比GMock简单得多。它在C++应用程序中也能很好地工作。
对于感兴趣的,这里是一个good article由迈克尔羽毛关于不同的接缝类型。
p8ekf7hl2#
最近我发现自己也遇到了同样的情况。我不得不为用C编写的库编写单元测试,而这些库又依赖于其他也是用C编写的库。所以我想使用 gmock 模拟所有依赖的函数调用。让我通过一个例子来解释我的方法。
假设要测试的代码(库A)调用另一个库
lib_x_function()
中的函数:因此,我想模拟库X。因此,我在文件
lib_x_mock.h
中编写了一个接口类和一个模拟类:另外,我创建了一个源文件(比如
lib_x_mock.cc
),它为实际的C函数定义了一个存根,这将调用mock方法,注意extern
对mock对象的引用。现在,在测试库A的测试文件中,我必须 globally 定义模拟对象,这样它既可以在您的测试中访问,也可以从
lib_x_mock.cc
访问,即lib_a_tests.cc:这种方法对我来说非常有效,我已经做了很多测试和一些模拟库。但是,我对创建一个全局模拟对象是否合适有一些疑问-我在separate question中问过这个问题,现在还在等待答案。除此之外,我对这个解决方案很满意。
**UPDATE:**全局对象的问题可以通过创建对象(例如,在测试夹具的构造器中),并仅在全局变量中存储指向该对象的指针来容易地补救。
然而,也请注意我对这个问题的替代答案,我刚刚张贴。
uttx8gqw3#
我一直在寻找一个解决方案,用googleMock模拟遗留的c-函数,而不改变现有的代码已经很长一段时间,最后几天我发现下面的文章真的很棒:https://www.codeproject.com/articles/1040972/using-googletest-and-googlemock-frameworks-for-emb
今天,我使用gmock编写了第一个c函数单元测试,并以raspberry Pi编程的bcm2835.c库(http://www.airspayce.com/mikem/bcm2835/)中的两个函数为例:下面是我的解决方案:我在Eclipse和Windows下使用gcc 4.8.3.,注意设置编译器选项-std = gnu ++11。
希望它会有帮助:)-对我来说,这是一个真正有效的解决方案。
gt0wga4j4#
您可以使用Cutie库来模仿C函数GoogleMock风格。
回购中有完整的样品,但只是尝一尝:
of1yzvn45#
在我进行单元测试的一个项目中有一个类似的案例,我的解决方案是创建两个make文件,一个用于生产,一个用于测试。
如果函数func_1()在头文件a. h中定义,并在a.cpp中实现,那么为了测试,您可以添加一个新的源文件a_testing. cpp,它将以存根的形式实现a. h中的所有函数。对于单元测试,只需编译并链接a_testing. cpp而不是a. cpp,测试代码将调用您的存根。
在a_testing. cpp中,您可以将调用转发到gmock对象,该对象将根据状态和参数照常设置期望和操作。
我知道它并不完美,但它可以工作并解决问题,而根本不需要更改产品代码或接口。
bybem2ql6#
在每个UT中,我们尝试验证特定的行为。
你应该在很难/不可能(我们需要隔离我们的单元)/花费大量时间(运行时间..)来模拟特定行为时假装一些东西。
显式地使用一个'C'函数意味着这个函数是你的单元的一部分(因此你不应该模仿它..)。在这个答案中,我解释了测试这个方法的主动性(在编辑中..)。在我看来,你应该用参数调用
func
,这些参数会使func_1
模拟你想要验证的行为。GMock
基于编译伪(宏),因此您不能这样做。要伪'C'方法,您必须使用不同的工具,如Typemock Isolator++。如果不想使用
Isolator++
,那么应该重构方法;将func
更改为func(int a, <your pointer the function>)
,然后使用指针代替func_1
。我在这个答案中的图表可能有助于决定处理你的情况的方式。
xmq68pz97#
这可能不完全适合您的情况,但是如果您发现自己编写的C代码需要存根(例如,您想存根一些I/O连接),您可以使用函数指针。
假设您有一个头文件和源文件,其中包含以下函数声明和定义:
some_file.h
some_file.c
现在,如果你想stub这个方法,你所要做的就是把这个方法转换成一个函数指针,你还需要调整.c文件,因为我们改变了函数,把它变成了一个函数指针。
some_file.h
some_file.c
您不必在其他地方调整函数调用,因为
func_1
将被简单地重定向到func_1_Impl
。现在来存根这个方法:
在你的
*_test.cc
文件(或者你的测试文件)中,你可以创建一个与some_file.h
接口相同的模拟类,然后用定义的模拟函数覆盖函数指针。一些文件测试.cc
此测试应通过,表明模拟工作正常。您还可以检查如果更改
EXPECT_CALL
调用(例如set.Times(AtLeast(2))
),测试是否会失败。注意:您可能会看到调整后的测试通过了
AtLeast(2)
,尽管这是错误的。您仍然应该在控制台中看到正确的错误消息。我希望这对你和其他有类似问题的人有帮助!