20 KiB
GMOCK
-
Avoid depricated
MOCK_METHDnandMOCK_CONST_METHODn -
Use
MOCK_METHOD() -
Use
Timeswhen want to expect how many times function was call (by default it expect once) -
Use
AtLeastTo expect n or more calls -
Use
WillOnceandWillRepeatedlyto perform some actions -
Use
SaveArgto save argument provided to mock function -
Use
InSequenceto perform sequenced actions - You can mock non-virtual function
-
Use
StrictMockwhen you need to be sure about every call of this mock -
Use
NiceMockwhen you don't care about function called for this mock -
Use
ON_CALLandWillByDefaultto perform some default action, when function will be called -
Use
DoAllto perform more then one action -
Use
Invoketo invoke funtion/lambda
MOCK_METHOD
MOCK_METHOD(return_type, name_of_function, arguments, parameters)
class MockTurtle : public Turtle {
public:
...
MOCK_METHOD(void, PenUp, (), (override));
MOCK_METHOD(void, PenDown, (), (override));
MOCK_METHOD(void, Forward, (int distance), (override));
MOCK_METHOD(void, Turn, (int degrees), (override));
MOCK_METHOD(void, GoTo, (int x, int y), (override));
MOCK_METHOD(int, GetX, (), (const, override));
MOCK_METHOD(int, GetY, (), (const, override));
};
- const - Makes the mocked method a const method. Required if overriding a const method.
- override - Marks the method with override. Recommended if overriding a virtual method.
- noexcept - Marks the method with noexcept. Required if overriding a noexcept method.
- Calltype(...) - Sets the call type for the method (e.g. to STDMETHODCALLTYPE), useful in Windows.
- ref(...) - Marks the method with the reference qualification specified. Required if overriding a method that has reference qualifications. Eg ref(&) or ref(&&).
Test class
Let's use once agin Foo and Bar class
class Bar {
public:
virtual ~Bar() = default;
virtual bool doOtherStuff(const std::string& str, int*, const std::vector<int>& vec) const {
// do some stuff
return false;
}
};
class MockBar : public Bar {
public:
~MockBar() override = default;
MOCK_METHOD(bool, doOtherStuff, (const std::string&, int*, const std::vector<int>&), (const override));
};
class Foo {
public:
Foo(std::unique_ptr<Bar> bar)
: val_(std::make_unique<int>(42)),
bar_(std::move(bar)) {}
bool doSth(const std::string& str) {
return bar_->doOtherStuff(str, val_.get(), {1, 2, 3, 4});
}
private:
std::unique_ptr<int> val_;
std::unique_ptr<Bar> bar_;
};
Times
TEST(ExampleTest, ShouldTest) {
auto mockBar = std::make_unique<MockBar>();
auto* mockBarPtr = mockBar.get();
Foo foo(std::move(mockBar));
EXPECT_CALL(*mockBarPtr, doOtherStuff).Times(2);
foo.doSth("Sth1");
foo.doSth("Sth2");
}
AtLeast
TEST(ExampleTest, ShouldTest) {
auto mockBar = std::make_unique<MockBar>();
auto* mockBarPtr = mockBar.get();
Foo foo(std::move(mockBar));
EXPECT_CALL(*mockBarPtr, doOtherStuff).Times(testing::AtLeast(2));
foo.doSth("Sth1");
foo.doSth("Sth2");
}
WillOnce and WillRepeatedly
TEST(ExampleTest, ShouldTest) {
auto mockBar = std::make_unique<MockBar>();
auto* mockBarPtr = mockBar.get();
Foo foo(std::move(mockBar));
// Dont do that. Next exceptaion will override first one!
// EXPECT_CALL(*mockBarPtr, doOtherStuff).WillOnce(Return(false));
// EXPECT_CALL(*mockBarPtr, doOtherStuff).WillOnce(Return(true));
// Correct one!
EXPECT_CALL(*mockBarPtr, doOtherStuff)
.WillOnce(Return(false))
.WillOnce(Return(true));
EXPECT_FALSE(foo.doSth("Sth1"));
EXPECT_TRUE(foo.doSth("Sth2"));
}
TEST(ExampleTest, ShouldTest) {
//...
EXPECT_CALL(*mockBarPtr, doOtherStuff)
.WillOnce(Return(false))
.WillOnce(Return(true))
.WillRepeatedly(Return(false));
EXPECT_FALSE(foo.doSth("Sth1"));
EXPECT_TRUE(foo.doSth("Sth2"));
EXPECT_FALSE(foo.doSth("Sth3"));
EXPECT_FALSE(foo.doSth("Sth4"));
}
Save arguments provided to functions (1)
We want to capture parameters provided to bar function.
class Bar {
public:
virtual ~Bar() = default;
virtual bool doOtherStuff(const std::string& str, int val, const std::vector<int>& vec) {
// do some stuff
return false;
}
};
class MockBar : public Bar {
public:
~MockBar() override = default;
MOCK_METHOD(bool, doOtherStuff, (const std::string&, int, const std::vector<int>&), (override));
};
class Foo {
public:
Foo(std::unique_ptr<Bar> bar)
: bar_(std::move(bar)) {}
bool doSth(const std::string& str) {
return bar_->doOtherStuff(str, 42, {1, 2, 3, 4});
}
private:
std::unique_ptr<Bar> bar_;
};
Save arguments provided to functions (2)
TEST(ExampleTest, ShouldTest) {
auto mockBar = std::make_unique<MockBar>();
auto* mockBarPtr = mockBar.get();
Foo foo(std::move(mockBar));
int val;
std::vector<int> vec;
// Also return true, instead of false like in original function
EXPECT_CALL(*mockBarPtr, doOtherStuff).
WillOnce(DoAll(SaveArg<1>(&val), SaveArg<2>(&vec), Return(true)));
EXPECT_TRUE(foo.doSth("Sth"));
EXPECT_EQ(val, 42);
const auto expected = std::vector<int>{1, 2, 3, 4};
EXPECT_EQ(vec, expected);
}
[----------] 1 test from ExampleTest
[ RUN ] ExampleTest.ShouldTest
[ OK ] ExampleTest.ShouldTest (0 ms)
[----------] 1 test from ExampleTest (0 ms total)
Save pointer provided to function
class Bar {
public:
virtual ~Bar() = default;
virtual bool doOtherStuff(const std::string& str, int* val, const std::vector<int>& vec) {
// do some stuff
return false;
}
};
TEST(ExampleTest, ShouldTest) {
auto mockBar = std::make_unique<MockBar>();
auto* mockBarPtr = mockBar.get();
Foo foo(std::move(mockBar));
int* val;
std::vector<int> vec;
// Capture by SaveArgPointee
EXPECT_CALL(*mockBarPtr, doOtherStuff).
WillOnce(DoAll(SaveArgPointee<1>(val), SaveArg<2>(&vec), Return(true)));
EXPECT_TRUE(foo.doSth("Sth"));
EXPECT_EQ(*val, 42);
const auto expected = std::vector<int>{1, 2, 3, 4};
EXPECT_EQ(vec, expected);
}
Capture non-copyable object
- There is a problem to capture non-copyable objects because we can't copy them!
- We need to make an ugly hack to capture this object -> move this object to our variable.
- This will be problematic when this object needs to be used in a function, but it will work when we used in on mock function because the argument will not be used later.
// Bar
bool doSth(const std::string& str) {
return bar_->doOtherStuff(str, std::make_unique<int>(42), {1, 2, 3, 4});
}
TEST(ExampleTest, ShouldTest) {
auto mockBar = std::make_unique<MockBar>();
auto* mockBarPtr = mockBar.get();
Foo foo(std::move(mockBar));
std::unique_ptr<int> val;
EXPECT_CALL(*mockBarPtr, doOtherStuff).WillOnce(DoAll(MoveObject<1>(&val), Return(true)));
EXPECT_TRUE(foo.doSth("Sth"));
EXPECT_EQ(*val, 42);
}
-
There is no such function in gtest, so we need to implement somehow
MoveObject
Move object
ACTION_TEMPLATE(MoveObject,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(pointer)) {
using PtrType = std::remove_cv_t<std::remove_reference_t<decltype(std::get<k>(args))>>;
// This unique_ptr will be deleted after function end
// so we need to capture it
*pointer = std::move(const_cast<PtrType&>(std::get<k>(args)));
}
When we only need a raw pointer from unique_ptr
ACTION_TEMPLATE(ExtractPtr,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(pointer)) {
*pointer = std::get<k>(args).get();
}
But we will lost it, because unique_ptr will be deleted after exit form mock function!
This is a very old way, the better one is to just lambda instead, I will show this later
InSequence (1)
TEST(ExampleTest, ShouldTest) {
auto mockBar = std::make_unique<MockBar>();
auto* mockBarPtr = mockBar.get();
Foo foo(std::move(mockBar));
testing::Sequence seq;
// Four expectations in sequence. There is no override like before
for (int i = 0; i < 4; ++i) {
EXPECT_CALL(*mockBarPtr, doOtherStuff)
.InSequence(seq)
.WillOnce(Return(i % 2));
}
EXPECT_FALSE(foo.doSth("Sth1"));
EXPECT_TRUE(foo.doSth("Sth2"));
EXPECT_FALSE(foo.doSth("Sth3"));
EXPECT_TRUE(foo.doSth("Sth4"));
}
InSequence (2)
This has the same behaviour like previous example
TEST(ExampleTest, ShouldTest) {
auto mockBar = std::make_unique<MockBar>();
auto* mockBarPtr = mockBar.get();
Foo foo(std::move(mockBar));
{
testing::InSequence seq;
// Four expectations in sequence. There is no override like before
for (int i = 0; i < 4; ++i) {
EXPECT_CALL(*mockBarPtr, doOtherStuff).WillOnce(Return(i % 2));
}
}
EXPECT_FALSE(foo.doSth("Sth1"));
EXPECT_TRUE(foo.doSth("Sth2"));
EXPECT_FALSE(foo.doSth("Sth3"));
EXPECT_TRUE(foo.doSth("Sth4"));
}
InSequence - branch out
testing::Sequence s1, s2;
EXPECT_CALL(foo, Method1())
.InSequence(s1, s2);
EXPECT_CALL(bar, Method2())
.InSequence(s1);
EXPECT_CALL(bar, Method3())
.InSequence(s2);
EXPECT_CALL(foo, Method4())
.InSequence(s2);
+---> Method2 (seq1)
(seq1 seq2) |
Method1----|
|
+---> Method3 ---> Method4 (seq2)
mock non-virtual function (1)
We have the following class
struct Packet {};
class ConcretePacketStream {
public:
void AppendPacket(Packet* new_packet) {}
const Packet* GetPacket(size_t packet_number) const {}
size_t NumberOfPackets() const {}
};
mock non-virtual function (2)
We can create mock and instead of dynamic polymorphism use static polymorphism (templates)
// A mock packet stream class. It inherits from no other, but defines
// GetPacket() and NumberOfPackets(). No need to add all functions like: AppendPacket
class MockPacketStream {
public:
// Do not add override!
MOCK_METHOD(const Packet*, GetPacket, (size_t packet_number), (const));
MOCK_METHOD(size_t, NumberOfPackets, (), (const));
};
// Now we can use static polymorphism to insert Mock class in a test,
// and real class in production code
template <class PacketStream>
class PacketReader {
public:
const Packet* ReadPackets(PacketStream* stream, size_t packet_num) {
return stream->GetPacket(packet_num);
}
};
mock non-virtual function (3)
Now in test we can use mock class
TEST(TestNonVirtualMethod, ShouldTest) {
MockPacketStream mock_stream;
EXPECT_CALL(mock_stream, GetPacket).WillOnce(Return(nullptr));
PacketReader<MockPacketStream> reader;
reader.ReadPackets(&mock_stream, 12);
}
And in production code the real one
ConcretePacketStream stream;
PacketReader<ConcretePacketStream> reader;
auto* packet = reader.ReadPackets(&stream, 12);
StrictMock
The usage of StrictMock is similar to normal mock, except that it makes all uninteresting calls failures:
class MockFoo : public Foo {
//...
MOCK_METHOD(void, Fun1, (), (override));
MOCK_METHOD(void, Fun2, (), (override));
};
TEST(SimpleTest, TestSth) {
StrictMock<MockFoo> mock_foo;
// When Fun2 will be also called it cause test failed
EXPECT_CALL(mock_foo, Fun1());
}
NiceMock
- The usage of `StrictMock` is similar to normal mock, except that it reject uninteresting calls (we will not see them while run test)
- NiceMock and StrictMock only affects uninteresting calls (calls of methods with no expectations); they do not affect unexpected calls (calls of methods with expectations, but they don’t match)
class MockFoo : public Foo {
//...
MOCK_METHOD(void, Fun1, (), (override));
MOCK_METHOD(void, Fun2, (), (override));
};
TEST(SimpleTest, TestSth) {
NiceMock<MockFoo> mock_foo;
// When Fun2 will be also called it will be ignored
EXPECT_CALL(mock_foo, Fun1());
}
ON_CALL and WillByDefault
We can do whatever we want when some mock method will be called. We can even save all types of arguments, or move objects to test them (call later).
When a function takes for instance non-copyable callback, and we need to capture it to continue testing, we can move it inside lambda! This is much better than the tricky template shown before.
TEST(ExampleTest, ShouldTest) {
auto mockBar = std::make_unique<MockBar>();
auto* mockBarPtr = mockBar.get();
Foo foo(std::move(mockBar));
// Nice way to capture all types of argument
int* ptr;
ON_CALL(*mockBarPtr, doOtherStuff)
.WillByDefault([&ptr](const std::string&, int* new_ptr, const std::vector<int>&) {
ptr = new_ptr;
return true;
});
EXPECT_CALL(*mockBarPtr, doOtherStuff);
EXPECT_TRUE(foo.doSth("Sth1"));
EXPECT_EQ(*ptr, 42);
}
DoAll
If we need to combine a few actions, we can do this inside doAll(...)
TEST(ExampleTest, ShouldTest) {
auto mockBar = std::make_unique<MockBar>();
auto* mockBarPtr = mockBar.get();
Foo foo(std::move(mockBar));
std::string str;
int* ptr;
EXPECT_CALL(*mockBarPtr, doOtherStuff)
.WillOnce(DoAll(
SaveArg<0>(&str),
SetArgPointee<1>(80), // Replace pointer value
SaveArgPointee<1>(ptr), // Capture value of arg1
Return(true)));
EXPECT_TRUE(foo.doSth("Sth1"));
EXPECT_EQ(str, "Sth1");
EXPECT_EQ(*ptr, 80);
}
Invoke (1)
Let's change a little MockBar
class MockBar : public Bar {
public:
~MockBar() override = default;
MOCK_METHOD(bool, doOtherStuff, (const std::string&, int*, std::function<void(int)>), (const override));
};
Now we want to run callback. We can do this without capture it!
EXPECT_CALL(*mockBarPtr, doOtherStuff)
.WillOnce(DoAll(
SaveArg<0>(&str),
SetArgPointee<1>(80), // Replace pointer value
SaveArgPointee<1>(ptr), // Capture value of arg1
InvokeArgument<2>(500), // Invoke callback
Return(true)));
Invoke (2)
class Helper {
public:
void validateArguments(const std::string& str, int* ptr, std::function<void(int)> callback) {
ASSERT_EQ(str.size(), 4);
EXPECT_EQ(str, "Sth1");
ASSERT_TRUE(ptr);
EXPECT_EQ(*ptr, 42);
ASSERT_TRUE(callback);
callback(50); // We can invoke callback here
}
};
TEST(ExampleTest, ShouldTest) {
auto mockBar = std::make_unique<MockBar>();
auto* mockBarPtr = mockBar.get();
Foo foo(std::move(mockBar));
Helper helper;
EXPECT_CALL(*mockBarPtr, doOtherStuff)
.WillOnce(DoAll(
Invoke(&helper, &Helper::validateArguments),
Return(true)));
EXPECT_TRUE(foo.doSth("Sth1"));
}
Exercise 2
Open project SHM and write test for class Store.cpp which will test it's interface. You need to mock Cargo class and check if you get correct result based on what you mock. Write mock in Presentation/exercises/SHM/tests/CargoMock.h for Cargo class.
Go to Presentation/exercises/SHM/build/test and run test using command ./SHM_Tests.