我有一个课程(比方说: 家长 ) strong>对象。
我想知道,如何在父方法调用中调用成员方法。
让我们看一个例子:
class Parent : public IParent
{
public:
Member() : member{} {}
void parent_method() override
{
member.member_method();
}
private:
Member member;
}
我想准备测试,检查是否使用 parent_method 调用 member_method > GTest / GMock。
重要:我想避免多态调用或任何动态分配 - 如果可能的话。
我有意在构造函数中传递一些Factory并构建正确的Member对象(真实或模拟),但它需要多态调用和动态分配。 我想避免这种开销。
有什么方法可以用干净的方式来做吗?
欢迎任何建议。提前谢谢。
答案 0 :(得分:1)
解决方案是使用模板完成。以下是Google模拟文档mock non-virtual methods using templates中推荐的内容的变体:
#include <iostream>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
using namespace std;
// YOUR SUT
class IParent
{
public:
virtual ~IParent() {};
virtual void parent_method() = 0;
};
class Member
{
public:
void member_method()
{
cout << "member_method\n";
}
};
template <class T = Member> // make it a template
class Parent : public IParent
{
public:
Parent() : member{} {}
void parent_method() override
{
member.member_method();
}
private:
using member_type = T;
member_type member; // member is now of type T (i.e. member_type)
template <class U>
friend U& GetMemberForTestMock(Parent<U>& parent); // necessary to set
// mock expectations
// for private member
};
// code in the test/mock file as this function is only for
// testing with mockMembers
template <class U>
U& GetMemberForTestMock(Parent<U>& parent)
{
return parent.member;
}
// Your mock class
class MockMember
{
public:
MOCK_CONST_METHOD0(member_method, void());
};
// Google Test
TEST(ParentTest, callsMemberMethodOnce)
{
auto parent = Parent<MockMember>{};
EXPECT_CALL(GetMemberForTestMock(parent), member_method()).Times(1);
parent.parent_method();
}
您可以通过修改friend
来消除Parent::Parent()
语句,以便可以将指针传递给Member或MockMember:
template <class T = Member> // make it a template
class Parent : public IParent
{
public:
using member_type = T;
Parent(member_type* m) : member{m} {}
void parent_method() override
{
member->member_method();
}
private:
member_type* member; // member is now of type T (i.e. member_type)
};
然后你可以这样测试:
TEST(ParentTest, callsMemberMethodOnceAgain)
{
auto member = MockMember{};
EXPECT_CALL(member, member_method()).Times(1);
auto parent = Parent<MockMember>{&member};
parent.parent_method();
}
修改Parent
界面以提供指定哪个Member
传递(或#34;注入&#34;测试模拟)的方法可能是个好主意它增加了模块性(即减少了两个对象之间的依赖关系)。它使您能够为Parent
提供不同的Member
提供不同的功能。如果你有更多的班级成员,这会让我担心你有几个模板参数。
你不应该嘲笑所有成员,甚至不要嘲笑所有成员#34;很多&#34;成员。大多数&#34;好&#34;具有一个职责的大小类具有很少的依赖性。您通常只需要模拟其他具有正交职责且您的课程依赖的类。一个好的设计试图最小化这些依赖性。如果您发现有许多类对其他类有很多依赖性,那么可能表明您的设计可以得到改进。
这给我们带来了性能,因为通过多态/继承提供这种模块化会因为额外的间接级别而付出代价。对于模板不是这种情况,因为在编译类型中选择了类型。但是,您可能不希望使用依赖项模板创建所有类,因此您必须达到平衡。很难&#34;猜测&#34;什么会显着影响整个系统的性能和多少。事实上,除了测量之外,没有可靠的方法。因此,我建议您采取最好的猜测,但要专注于良好的设计,并使您的代码可读并且正常工作。然后,在测量之后,如果存在性能问题,请修复它们。很大程度上取决于您的域名,但根据我的经验,这种间接性很少是性能问题的原因。
注意:我测试了使用gcc 7.2.0版(带有C ++ 17标志)和googletest 1.8.0提供的代码。