如何模拟依赖的成员变量?
How to mock a member variable of dependency?
我有一个 class 和成员:
class A
{
B obj;
public:
int f(int i){return obj.g(i);}
}
这里 B obj
是一个依赖项,需要 运行-time 从文件创建。在我对 class A 的单元测试中,我希望模拟 B obj
,函数 g
类型为 int(int)
。
如何编写我的测试代码,模拟 B obj
,然后测试 A::f
。
非常感谢。
你不能用你的代码来做。您已经在 A
class 中硬编码了您的依赖项。为了使模拟成为可能,您必须使用一些依赖注入模式。一种可能的方法是有一个指针(更聪明)指向你的 B
class 并且在 A
构造函数中你将获得一个指向 B
的指针,你将初始化你的内部 B*
。这样你就可以在你的测试中放置一个模拟对象。
为此,使用 B 的指针而不是 class A
中的对象并将您的单元测试 class (FixtureA
) 作为 friend class
in [=16] =].
class A
{
B *obj;
public:
int f(int i){return obj.g(i);}
friend class FixtureA;
};
在FixtureA.h
中你可以有如下代码
class FixtureA
{
public:
void Testf();
}
在FixtureA.cpp
TEST_F(FixtureA , Testf)
{
Testf();
}
void FixtureA::Testf()
{
A objA;
objA.obj = new BMock();
objA.f(2);
}
在 BMock class
中,您可以模拟 g()
函数。
您需要使用依赖注入来实现这一点。为此,让 class B
从接口继承,并让 class A
持有指向该接口的指针:
class IB
{
public:
virtual void g(int i) = 0;
};
class B : public IB
{
public:
void g(int i) {
// this is your real implementation
}
};
此外,要在 class A
中启用依赖注入,请添加适当的构造函数或 setter 方法:
class A
{
private:
IB *obj;
public:
A() : obj(nullptr) {}
// You don't need both the constructor and setter, one is enough
A(IB *pB) : obj(pB) {}
// void setB(IB *pB) { obj = pB; }
int f(int i) { return obj->g(i); }
};
现在,在您的生产代码中,您创建一个 class B
的对象并将其传递给 class A
对象(假设我们正在使用构造函数注入):
B b;
A a(&b);
在测试阶段,您创建了一个模拟 class BMock
并将该 class 的对象传递给 class A
对象:
class BMock : public IB
{
public:
MOCK_METHOD1(g, int(int));
};
TEST(ATests, TestCase1)
{
BMock bmock;
A a(&bmock);
// Now you can set expectations on mock object, for example that g will
// return 100 when it receives 50 as argument
EXPECT_CALL(bmock, g(50)).WillOnce(Return(100));
// Now act by calling A::f, which will in turn call g from mock object,
// and assert on function return value
ASSERT_EQ(a.f(50), 100);
}
我有一个 class 和成员:
class A
{
B obj;
public:
int f(int i){return obj.g(i);}
}
这里 B obj
是一个依赖项,需要 运行-time 从文件创建。在我对 class A 的单元测试中,我希望模拟 B obj
,函数 g
类型为 int(int)
。
如何编写我的测试代码,模拟 B obj
,然后测试 A::f
。
非常感谢。
你不能用你的代码来做。您已经在 A
class 中硬编码了您的依赖项。为了使模拟成为可能,您必须使用一些依赖注入模式。一种可能的方法是有一个指针(更聪明)指向你的 B
class 并且在 A
构造函数中你将获得一个指向 B
的指针,你将初始化你的内部 B*
。这样你就可以在你的测试中放置一个模拟对象。
为此,使用 B 的指针而不是 class A
中的对象并将您的单元测试 class (FixtureA
) 作为 friend class
in [=16] =].
class A
{
B *obj;
public:
int f(int i){return obj.g(i);}
friend class FixtureA;
};
在FixtureA.h
中你可以有如下代码
class FixtureA
{
public:
void Testf();
}
在FixtureA.cpp
TEST_F(FixtureA , Testf)
{
Testf();
}
void FixtureA::Testf()
{
A objA;
objA.obj = new BMock();
objA.f(2);
}
在 BMock class
中,您可以模拟 g()
函数。
您需要使用依赖注入来实现这一点。为此,让 class B
从接口继承,并让 class A
持有指向该接口的指针:
class IB
{
public:
virtual void g(int i) = 0;
};
class B : public IB
{
public:
void g(int i) {
// this is your real implementation
}
};
此外,要在 class A
中启用依赖注入,请添加适当的构造函数或 setter 方法:
class A
{
private:
IB *obj;
public:
A() : obj(nullptr) {}
// You don't need both the constructor and setter, one is enough
A(IB *pB) : obj(pB) {}
// void setB(IB *pB) { obj = pB; }
int f(int i) { return obj->g(i); }
};
现在,在您的生产代码中,您创建一个 class B
的对象并将其传递给 class A
对象(假设我们正在使用构造函数注入):
B b;
A a(&b);
在测试阶段,您创建了一个模拟 class BMock
并将该 class 的对象传递给 class A
对象:
class BMock : public IB
{
public:
MOCK_METHOD1(g, int(int));
};
TEST(ATests, TestCase1)
{
BMock bmock;
A a(&bmock);
// Now you can set expectations on mock object, for example that g will
// return 100 when it receives 50 as argument
EXPECT_CALL(bmock, g(50)).WillOnce(Return(100));
// Now act by calling A::f, which will in turn call g from mock object,
// and assert on function return value
ASSERT_EQ(a.f(50), 100);
}