googlemock 如何在测试中使用模拟
googlemock how to use mocking in test
我是 google mock 的初学者,我不确定如何使用它和概念。
如果我正在尝试测试来自 class 的方法,该方法正在调用来自不同 class 的其他方法。
我是否需要从我的测试方法调用的这个不同的 classes 中模拟所有这些方法。
这是一个例子:
class A {
public:
A () {}
int setnum(int num) {//do some stuff return 1 or 0//
}
private:
int _num;
};
class B {
public:
B (){}
int init(A *a, int number){
if(a->setnum(number))
return 1;
return 0;
}
void setNum(int num){_num=num;}
private:
A *_a;
int _num;
};
class C {
public:
int doSoemthing(A *a, int number){
if (domore(a,number))
return 1;
return 0;
}
int domore(A *a, int number){
if(_b.init(a,number))
return 1;
return 0;
;}
private:
B _b;
};
我是否需要模拟 class A 和 B 中测试我的测试方法所需的所有方法?
或者我可以只模拟一个 Class ,然后测试这个 class 是否有效。
我不是 100% 确定,但在您的示例中,您根本不必使用模拟。您可以在这里非常轻松地创建对象。
当我希望调用某些方法并且应该 return 特定值时,我会使用模拟 - 我不是在测试这个方法,而是例如 if-statement:
A a;
if(a.method())
{
// some logic
}
- 为了操纵 if 会得到什么,我会使用这样的模拟:
EXPECT_CALL(aMock.method()).WillOnce(Return(true));
但是您可以在更多情况下使用它(例如:您可以避免创建非常大的 class 并将其替换为模拟对象)。
为了使用模拟测试 C class,您需要为依赖项引入一个接口,而不是在 C class 中使用(此处添加了 BIface)。然后你需要使用 BIface 的依赖注入到 C class (通过添加的构造函数)。有了它,您将能够测试 B 和 C classes 的交互。 IMO A class 不需要在 CTest 中模拟(但很可能需要在 BTest 中进行测试)
class A {
public:
A() {} // not needed
int setnum(int num) { // do some stuff return 1 or 0//
}
private:
int _num;
};
class BIface {
public:
virtual ~BIface() = default;
virtual int init(A *a, int number) = 0;
virtual void setNum(int num) = 0;
};
class B : public BIface {
public:
B() {} // not needed
int init(A *a, int number) override {
if (a->setnum(number))
return 1;
return 0;
}
void setNum(int num) override {
_num = num;
}
private:
A *_a;
int _num;
};
class C {
public:
C(BIface &b) : _b{b} {}
int doSoemthing(A *a, int number) {
if (domore(a, number))
return 1;
return 0;
}
int domore(A *a, int number) {
if (_b.init(a, number))
return 1;
return 0;
;
}
private:
BIface &_b;
};
class BIfaceMock : public BIface {
public:
MOCK_METHOD2(init, int(A *, int));
MOCK_METHOD1(setNum, void(int));
};
TEST(CTest, givenDoingMoreWhenInitOfBReturnOneThenReturnOne) {
// can be done in CTest ctor if more tests are needed to avoid code duplciation
BIfaceMock bMock{};
A a{}; // `a` doesn't need to be mocked in CTest. It shall be mocked in BTest as it is dependency of B class, not C class
C testedObject{bMock}; // dependency injection of BFace to C
const auto SOME_INT_PARAM = 42;
// Eq mather is used to match both &a and SOME_INT_PARAM. This confirms proper parameters were passed to init
EXPECT_CALL(bMock, init(&a, SOME_INT_PARAM)).WillOnce(Return(1));
ASSERT_EQ(1, testedObject.domore(&a, SOME_INT_PARAM));
}
我是 google mock 的初学者,我不确定如何使用它和概念。
如果我正在尝试测试来自 class 的方法,该方法正在调用来自不同 class 的其他方法。 我是否需要从我的测试方法调用的这个不同的 classes 中模拟所有这些方法。 这是一个例子:
class A {
public:
A () {}
int setnum(int num) {//do some stuff return 1 or 0//
}
private:
int _num;
};
class B {
public:
B (){}
int init(A *a, int number){
if(a->setnum(number))
return 1;
return 0;
}
void setNum(int num){_num=num;}
private:
A *_a;
int _num;
};
class C {
public:
int doSoemthing(A *a, int number){
if (domore(a,number))
return 1;
return 0;
}
int domore(A *a, int number){
if(_b.init(a,number))
return 1;
return 0;
;}
private:
B _b;
};
我是否需要模拟 class A 和 B 中测试我的测试方法所需的所有方法? 或者我可以只模拟一个 Class ,然后测试这个 class 是否有效。
我不是 100% 确定,但在您的示例中,您根本不必使用模拟。您可以在这里非常轻松地创建对象。
当我希望调用某些方法并且应该 return 特定值时,我会使用模拟 - 我不是在测试这个方法,而是例如 if-statement:
A a;
if(a.method())
{
// some logic
}
- 为了操纵 if 会得到什么,我会使用这样的模拟:
EXPECT_CALL(aMock.method()).WillOnce(Return(true));
但是您可以在更多情况下使用它(例如:您可以避免创建非常大的 class 并将其替换为模拟对象)。
为了使用模拟测试 C class,您需要为依赖项引入一个接口,而不是在 C class 中使用(此处添加了 BIface)。然后你需要使用 BIface 的依赖注入到 C class (通过添加的构造函数)。有了它,您将能够测试 B 和 C classes 的交互。 IMO A class 不需要在 CTest 中模拟(但很可能需要在 BTest 中进行测试)
class A {
public:
A() {} // not needed
int setnum(int num) { // do some stuff return 1 or 0//
}
private:
int _num;
};
class BIface {
public:
virtual ~BIface() = default;
virtual int init(A *a, int number) = 0;
virtual void setNum(int num) = 0;
};
class B : public BIface {
public:
B() {} // not needed
int init(A *a, int number) override {
if (a->setnum(number))
return 1;
return 0;
}
void setNum(int num) override {
_num = num;
}
private:
A *_a;
int _num;
};
class C {
public:
C(BIface &b) : _b{b} {}
int doSoemthing(A *a, int number) {
if (domore(a, number))
return 1;
return 0;
}
int domore(A *a, int number) {
if (_b.init(a, number))
return 1;
return 0;
;
}
private:
BIface &_b;
};
class BIfaceMock : public BIface {
public:
MOCK_METHOD2(init, int(A *, int));
MOCK_METHOD1(setNum, void(int));
};
TEST(CTest, givenDoingMoreWhenInitOfBReturnOneThenReturnOne) {
// can be done in CTest ctor if more tests are needed to avoid code duplciation
BIfaceMock bMock{};
A a{}; // `a` doesn't need to be mocked in CTest. It shall be mocked in BTest as it is dependency of B class, not C class
C testedObject{bMock}; // dependency injection of BFace to C
const auto SOME_INT_PARAM = 42;
// Eq mather is used to match both &a and SOME_INT_PARAM. This confirms proper parameters were passed to init
EXPECT_CALL(bMock, init(&a, SOME_INT_PARAM)).WillOnce(Return(1));
ASSERT_EQ(1, testedObject.domore(&a, SOME_INT_PARAM));
}