使用MOCK_METHOD 宏生成mock方法。MOCK_METHOD 宏有三到四个参数,前三个参数为函数签名分成的三部分(返回值,函数名,参数),第四个参数为以下一个或多个,逗号分隔:
MOCK_METHOD 形如:MOCK_METHOD(int, my_func, (int x, string y), (const, override));
不管base class中函数的属性是哪种,mock方法必须都是public。因为这样ON_CALL和EXPECT_CALL可以在mock类外访问。
mock非虚函数的mock类除了使用MOCK_METHOD 定义的mock函数签名一样外,其他和原类没有任何关系了。
class ConcretePacketStream {
public:
void AppendPacket(Packet* new_packet);
const Packet* GetPacket(size_t packet_number) const;
size_t NumberOfPackets() const;
};
class MockPacketStream {
public:
MOCK_METHOD(const Packet*, GetPacket, (size_t packet_number), (const));
MOCK_METHOD(size_t, NumberOfPackets, (), (const));
};
实际上相当于重新写了不相关的mock类,只是保持了类函数签名一样。在mock类中可以按实际需要mock函数,不需要mock原类中的所有函数。
无法mock一个自由函数(不是类的成员函数都叫自由函数),但是可以通过以下方式实现:
class FileInterface {
public:
...
virtual bool Open(const char* path, const char* mode) = 0;
};
class File : public FileInterface {
public:
...
bool Open(const char* path, const char* mode) override {
return OpenFile(path, mode);
}
};
::testing::MockFunction
有两个mock方法:
R Call(T1, ..., Tn)
std::function AsStdFunction()
示例
TEST(FooTest, RunsCallbackWithBarArgument) {
MockFunction<int(string)> mock_function; // 声明MockFunction对象,自由函数的签名为int xx(string);
EXPECT_CALL(mock_function, Call("bar")).WillOnce(Return(1)); // 这里指定期望的调用
std::function<int(string)> f = mock_function.AsStdFunction(); // 取出mock函数并调用
EXPECT_EQ(f("bar"), 11);
}
TEST(...) {
MockFoo mock_foo;
EXPECT_CALL(mock_foo, DoThis());
... code that uses mock_foo ...
}
如果mock函数没有EXPECT_CALL但是被调用了。这种被称为不感兴趣的调用,会有告警信息。如下:
如果要忽略这种信息,可以使用NiceMock
代替mock_foo
:
NiceMock
是MockFoo的一个子类。以下方式调用完之后没有uninsterestring信息。
using ::testing::NiceMock;
TEST(test_override, mock_override02) {
NiceMock<MockFoo> foo; // 使用NiceMock代替MockFoo
EXPECT_CALL(foo, Add(::testing::_))
.Times(1)
.WillRepeatedly(testing::Return(12));
EXPECT_EQ(foo.DoThis(), 12);
}
StrictMock 的用法和NiceMock一样,期望所有的不感兴趣的调用失败。(看输出结果和NiceMock基本一样,不知道有啥区别?)
注意事项:
NiceMock
and StrictMock
只作用于使用MOCK_METHOD 宏定义的mock函数中,如果mock函数定义在MockFoo的base类中,NiceMock或StrictMock不会影响它。NiceMock
和 StrictMock
可能不会正常工作有时候要mock的方法有很多入参,这些入参大部分不需要,可以通过以下示例中的方式进行在mock函数中进行简化
class LogSink {
public:
virtual void send(int severity, const char* full_filename,
const char* base_filename, int line,
const int* tm_time,
const char* message, size_t message_len) = 0;
};
class ScopedMockLog : public LogSink {
public:
void send(int severity, const char* full_filename,
const char* base_filename, int line, const int* tm_time,
const char* message, size_t message_len) override {
Log(severity, full_filename, base_filename);
std::cout << "ScopedMockLog::send" << std::endl;
}
MOCK_METHOD(void, Log, (int severity, const string& file_path, const string& message));
};
TEST(test_simplify, mock_simplify) {
mock_simplify::ScopedMockLog log;
EXPECT_CALL(log, Log(1, "a.txt", "bbb")).WillOnce([](int x, const string& file_path, const string& message){
std::cout << "x: " << x << ", file_path is: " << file_path << ", message: " << message << std::endl;
});
log.Log(1, "a.txt", "bbb");
}
分析:接口类LogSink 的send方法中我们只用到severity,file_path和message这三个参数,其他不需要,可以通过在派生的mock类中实现这个虚函数而不是直接mock它。并定义一个只需要这三个参数的新函数(通过MOCK_METHOD定义)在后续测试程序中使用就OK了。
如果要将一个类的mock函数实现转交给其他类(fake类或其他对象),可以通过以下示例方式
// 定义原类
class Foo {
public:
virtual ~Foo() {}
virtual char DoThis(int n) = 0;
virtual void DoThat(const char* s, int * p) = 0;
};
// Fake为fake类,或者其他从Foo派生下来的类
class FakeFoo : public Foo {
public:
char DoThis(int n) override {
return (n > 0) ? '+' : (n < 0) ? '-': '0';
}
void DoThat(const char* s, int * p) override {
*p = strlen(s);
}
};
在Mock类中使用其他类(如FakeFoo)代理实现
class MockFoo : public Foo {
public:
MOCK_METHOD(char, DoThis, (int n), (override));
MOCK_METHOD(void, DoThat, (const char* s, int * p), (override));
void DelegateToFake() {
ON_CALL(*this, DoThis).WillByDefault([this] (int n) {
return fake_.DoThis(n);
});
ON_CALL(*this, DoThat).WillByDefault([this] (const char* s, int* p) {
fake_.DoThat(s, p);
});
};
private:
FakeFoo fake_;
};
TEST函数中可以直接使用,不需要指定action
TEST(test_mock_delegatetofake, mock_delegatetofake01) {
delegate_fake::MockFoo foo;
foo.DelegateToFake();
EXPECT_CALL(foo, DoThis(5));
EXPECT_CALL(foo, DoThat(_, _));
int n = 0;
EXPECT_EQ('+', foo.DoThis(5));
foo.DoThat("Hi", &n);
EXPECT_EQ(2, n);
}
class PFoo {
public:
virtual ~PFoo() {}
virtual void Pure(int n) = 0;
virtual int Concrete(const char* str) { return 1; }
};
这个类中Concrete不是纯虚函数,如果直接想使用该函数作为mock函数
class PMockFoo : public PFoo {
public:
// Mocking a pure method.
MOCK_METHOD(void, Pure, (int n), (override));
// Mocking a concrete method. Foo::Concrete() is shadowed.
MOCK_METHOD(int, Concrete, (const char* str), (override));
};
TEST(test_mock_delegatetofake, mock_delegatetoparent) {
delegate_fake::PMockFoo foo;
EXPECT_CALL(foo, Concrete).WillOnce([&foo](const char* str) {
return foo.PFoo::Concrete(str);
});
EXPECT_EQ(foo.Concrete("hello"), 2);
}
ON_CALL(foo, Concrete).WillByDefault([&foo](const char* str) {
return foo.Foo::Concrete(str);
});