我知道这个问题的第一部分是asked before,但那是很久以前的事了:)。我想知道在模拟非虚拟方法和C函数时,任何开源模拟框架的平均时间是否赶上了Typemock Isolator ++。我最感兴趣的是Linux下的gcc。到目前为止,我对模拟访问器感兴趣(这样我可以模拟模拟对象中的状态 - 见下文)并从其他库中替换C函数(select,pcap_ *等)。
class Foo {
public:
...
bool IsCondition() { return condition; };
...
private:
bool condition;
}
// I want a framework that allows me to do something like this:
TEST(TestFoo) {
MOCK_INTERFACE(Foo) mock_foo;
EXPECT_CALL(mock_foo, IsCondition).returns(true);
EXPECT(mock_foo.IsCondition());
}
答案 0 :(得分:5)
GMock支持mocking non-virtual methods所谓的hi-perf依赖注入。
从上面的链接中,要点是使用模板:
template <class PacketStream>
void CreateConnection(PacketStream* stream) { ... }
template <class PacketStream>
class PacketReader {
public:
void ReadPackets(PacketStream* stream, size_t packet_num);
};
然后,您可以在生产代码中使用CreateConnection()和PacketReader,并在测试中使用CreateConnection()和PacketReader。
对于C函数,他们推荐接口,所以可能不是你想要的。但是,如果您有单独的库,则始终可以链接到测试库,该测试库包含与部署库具有相同签名的功能。你甚至可以用LD_PRELOAD动态地做它,如果你感觉特别大胆的话。这听起来像很多链接到我。
Cxxtest,如果您在advanced features的第8.1节中查看,则支持使用某些宏来更轻松地使用/创建界面:
从该链接:
CXXTEST_MOCK_GLOBAL( time_t, /* Return type */
time, /* Name of the function */
( time_t *t ), /* Prototype */
( t ) /* Argument list */ );
8.1.2. Mock Functions in Tested Code
测试代码使用模拟全局函数,而不是直接使用全局函数。您可以在T(for Test)命名空间中访问模拟函数,因此测试的代码调用T :: time()而不是time()。这相当于使用抽象接口而不是具体类。
// rand_example.cpp
#include <time_mock.h>
int generateRandomNumber()
{
return T::time( NULL ) * 3;
}
过去我对Cxxtest方法运气不错。
答案 1 :(得分:0)
使用最近的GCC(例如4.6),您可以在C中编写插件,或者为MELT编写扩展名。
但是,要自定义GCC(通过C中的插件或MELT中的扩展),您需要部分理解其内部表示(Gimple和Tree-s),这需要时间(可能超过一周的工作)。因此,如果你有足够大的代码库值得付出努力,这种方法就有意义了。
答案 2 :(得分:0)
如果您禁用内联并使用与位置无关的代码进行编译,则ELFSpy支持替换(成员)函数。
您的测验可以写成如下
// define alternate implementation for Foo::IsCondition
bool IsConditionTest(Foo*) { return true; }
int main(int argc, char** argv)
{
// initialise ELFSpy
spy::initialise(argc, argv);
// create a handle for intercepting Foo::IsCondition calls
auto method_spy = SPY(&Foo::IsCondition);
// relink original method to different implementation
auto method_fake = spy::fake(method_spy, &IsConditionTest);
// capture return value(s) from calls to Foo::IsCondition
auto returned = spy::result(method_spy);
// execute your test
Foo foo;
bool simulate = foo.IsCondition(); // calls IsConditionTest instead
// check it worked
assert(returned.value() == true);
}
以上示例在运行时有效地重新链接了代码,以调用IsConditionTest而不是Foo :: IsCondition,因此您可以将其替换为所需的任何内容。函数/方法也可以用lambda代替。
有关详细信息,请参见https://github.com/mollismerx/elfspy/wiki。免责声明:我写了ELFSpy。