我想为我们的项目创建一个单元测试环境。但我迷失了如何为班级成员创建模拟。我想用一个例子来解释我的问题。
在我的旧项目中,我们使用的模拟选择机制在我看来非常难看。这是老方法:
class member {
};
class member_mock_1 {
};
class member_mock_2 {
};
class parent {
#if defined UNIT_TEST_1
typedef member_t member_mock_1;
#elif defined UNIT_TEST_2
typedef member_t member_mock_2;
#else
typedef member_t member;
#endif
private:
member_t mem;
};
第一个问题是模拟成员对象的类,在父类中输入或输出typedefing是否正确?什么是最佳做法?如果我想使用单元测试框架,比如gtest,我应该使用这种方式还是有其他方法来嘲笑成员?
注1:如果虚拟机制被激活,可以创建基类以简化模拟,如果类是pod或其他什么,我不想使用这种机制。
注2:我也发现丑陋的传递成员类型作为模板参数,一切都成为项目中的模板。我不想那样做。这是一个例子:
template <typename M>
class parent {
private:
M mem;
};
#if defined UNIT_TEST_1
typedef parent_t parent<member_mock_1>;
#elif defined UNIT_TEST_2
typedef parent_t parent<member_mock_2>;
#else
typedef parent_t parent<member>;
#endif
以下是我建议的方法:
member_mock_1.hpp
class member_mock_1 {
};
member_mock_2.hpp
class member_mock_2 {
};
mock.hpp
template <typename TYPE>
struct mock { using type = TYPE; };
#define ENABLE_MOCKING(NamE) \
using NamE ## _t = mock<NamE>::type
member_mock.hpp
#if define UNIT_TEST_1
template<>
struct mock<member> { using type = member_mock_1 };
#endif
#if define UNIT_TEST_2
template<>
struct mock<member> { using type = member_mock_2 };
#endif
member.hpp
class member {
};
ENABLE_MOCKING(member);
parent.hpp
class parent {
private:
member_t mem;
};
我上面提到的方法适用于普通类。对于模板类,我认为应该完成一些额外的工作。
所以作为结论,我建议像上面这样的单元测试结构。可能没有必要,还有一些其他机制或方法来满足这一要求。也许我还在重新发明轮子:(
请提供一种嘲笑某个班级成员的方法。
感谢。
答案 0 :(得分:2)
是的,你正在重新发明代码看起来非常混乱:
#if defined UNIT_TEST_1
typedef parent_t parent<member_mock_1>;
#elif defined UNIT_TEST_2
typedef parent_t parent<member_mock_2>;
#else
typedef parent_t parent<member>;
#endif
有几种工具可供选择。 我使用Typemock Isolator ++,因为你可以嘲笑几乎所有东西,而不用触及你的生产。 另外一件事,你在模拟上设置的行为只会在测试范围内应用,因此每个测试都有一个独立的设置。
您可以访问该成员,即使该成员是私有的:
member* mock_member = FAKE<member>;
parent* my_parent = new parent();
ISOLATOR_SET_MEMBER(my_parent, mem, mock_member);
轻松搞定:
member* get_member;
ISOLATOR_GET_MEMBER(my_parent, mem, get_member);
此外,它允许伪造抽象类,全局方法,纯虚方法,私有和受保护方法,为它设置行为。此外,访问隐藏的数据成员并调用它们。查看this了解详情。
答案 1 :(得分:1)
我遇到了类似的情况 - 将单元测试引入遗留的C ++项目。为此,我使用了很多预处理程序指令以及Google Test和Google Mock。特别是,如果我面对你的例子,我会这样做:
#if defined UNIT_TEST
class imember
{
virtual void a_method() = 0;
};
#endif
class member
#if defined UNIT_TEST
: public imember
#endif
{
void a_method()
{
// do something
};
};
class parent {
public:
#if defined UNIT_TEST
parent(imember mem) : mem_(mem) {};
#endif
private:
#if defined UNIT_TEST
imember mem_;
#else
member mem_;
#endif
};
现在,使用Google Mock定义模拟类:
class mockmember : public imember
{
public:
MOCK_METHOD0(a_method, void());
};
模拟课程现已准备就绪。使用Google Test定义测试方案:
class parenttest : public testing::Test
{
public:
parenttest() : member_(mockmember()), parent_(member_) {}
virtual void SetUp() {}
virtual void TearDown() {}
protected:
parent parent_;
mockmember member_;
};
TEST_F(parenttest, a_func)
{
EXPECT_CALL(member_, a_method());
int ret = parent_.a_func();
ASSERT_EQ(0, ret);
}
答案 2 :(得分:0)
免责声明,我在Typemock工作。
山姆是完全正确的。 此外,您不需要为每个单元测试创建3个不同的member_mock类。您可以简单地设置行为,例如,对于成员中的某些私有方法:
member* mock_member = FAKE<member>;
PRIVATE_WHEN_CALLED(member, somePrivateMethod()).Return(0);
接下来使用PRIVATE_WHEN_CALLED(mock_member, somePrivateMethod())
会使somePrivateMethod()的行为超载,因此,不要创建大量不同的模拟类,只需根据需要更改行为。
希望它对你有用!