681 lines
No EOL
20 KiB
Markdown
681 lines
No EOL
20 KiB
Markdown
## GMOCK
|
||
|
||
* <!-- .element: class="fragment fade-in" --> Avoid depricated <code>MOCK_METHDn</code> and <code>MOCK_CONST_METHODn</code>
|
||
* <!-- .element: class="fragment fade-in" --> Use <code>MOCK_METHOD()</code>
|
||
* <!-- .element: class="fragment fade-in" --> Use <code>Times</code> when want to expect how many times function was call (by default it expect once)
|
||
* <!-- .element: class="fragment fade-in" --> Use <code>AtLeast</code> To expect <b>n</b> or more calls
|
||
* <!-- .element: class="fragment fade-in" --> Use <code>WillOnce</code> and <code>WillRepeatedly</code> to perform some actions
|
||
* <!-- .element: class="fragment fade-in" --> Use <code>SaveArg</code> to save argument provided to mock function
|
||
* <!-- .element: class="fragment fade-in" --> Use <code>InSequence</code> to perform sequenced actions
|
||
* <!-- .element: class="fragment fade-in" --> You can mock non-virtual function
|
||
* <!-- .element: class="fragment fade-in" --> Use <code>StrictMock</code> when you need to be sure about every call of this mock
|
||
* <!-- .element: class="fragment fade-in" --> Use <code>NiceMock</code> when you don't care about function called for this mock
|
||
* <!-- .element: class="fragment fade-in" --> Use <code>ON_CALL</code> and <code>WillByDefault</code> to perform some default action, when function will be called
|
||
* <!-- .element: class="fragment fade-in" --> Use <code>DoAll</code> to perform more then one action
|
||
* <!-- .element: class="fragment fade-in" --> Use <code>Invoke</code> to invoke funtion/lambda
|
||
|
||
<!-- .slide: style="font-size: 0.9em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## MOCK_METHOD
|
||
|
||
MOCK_METHOD(return_type, name_of_function, arguments, parameters)
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
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));
|
||
};
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
* <!-- .element: class="fragment fade-in" --> const - Makes the mocked method a const method. Required if overriding a const method.
|
||
* <!-- .element: class="fragment fade-in" --> override - Marks the method with override. Recommended if overriding a virtual method.
|
||
* <!-- .element: class="fragment fade-in" --> noexcept - Marks the method with noexcept. Required if overriding a noexcept method.
|
||
* <!-- .element: class="fragment fade-in" --> Calltype(...) - Sets the call type for the method (e.g. to STDMETHODCALLTYPE), useful in Windows.
|
||
* <!-- .element: class="fragment fade-in" --> ref(...) - Marks the method with the reference qualification specified. Required if overriding a method that has reference qualifications. Eg ref(&) or ref(&&).
|
||
<!-- .slide: style="font-size: 0.9em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## Test class
|
||
|
||
Let's use once agin `Foo` and `Bar` class
|
||
|
||
```C++
|
||
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_;
|
||
};
|
||
|
||
```
|
||
<!-- .slide: style="font-size: 0.63em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## Times
|
||
|
||
```C++
|
||
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");
|
||
}
|
||
```
|
||
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.9em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## AtLeast
|
||
|
||
```C++
|
||
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");
|
||
}
|
||
```
|
||
|
||
<!-- .element: class="fragment fade-in" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## WillOnce and WillRepeatedly
|
||
|
||
```C++
|
||
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"));
|
||
}
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
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"));
|
||
}
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.68em" -->
|
||
|
||
___
|
||
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## Save arguments provided to functions (1)
|
||
|
||
We want to capture parameters provided to bar function.
|
||
|
||
```C++
|
||
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_;
|
||
};
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.65em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## Save arguments provided to functions (2)
|
||
|
||
```C++
|
||
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);
|
||
}
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```
|
||
[----------] 1 test from ExampleTest
|
||
[ RUN ] ExampleTest.ShouldTest
|
||
[ OK ] ExampleTest.ShouldTest (0 ms)
|
||
[----------] 1 test from ExampleTest (0 ms total)
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.78em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## Save pointer provided to function
|
||
|
||
```C++
|
||
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;
|
||
}
|
||
};
|
||
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
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);
|
||
}
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.7em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## Capture non-copyable object
|
||
|
||
* <!-- .element: class="fragment fade-in" --> There is a problem to capture non-copyable objects because we can't copy them!
|
||
* <!-- .element: class="fragment fade-in" --> We need to make an ugly hack to capture this object -> move this object to our variable.
|
||
* <!-- .element: class="fragment fade-in" --> 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.
|
||
|
||
```C++
|
||
// 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);
|
||
}
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
* <!-- .element: class="fragment fade-in" --> <b>There is no such function in gtest, so we need to implement somehow <code>MoveObject</code></b>
|
||
<!-- .slide: style="font-size: 0.7em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## Move object
|
||
|
||
```C++
|
||
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)));
|
||
}
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
When we only need a raw pointer from `unique_ptr`
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
ACTION_TEMPLATE(ExtractPtr,
|
||
HAS_1_TEMPLATE_PARAMS(int, k),
|
||
AND_1_VALUE_PARAMS(pointer)) {
|
||
*pointer = std::get<k>(args).get();
|
||
}
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
But we will lost it, because `unique_ptr` will be deleted after exit form mock function!
|
||
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.8em" -->
|
||
|
||
<b>This is a very old way, the better one is to just lambda instead, I will show this later</b>
|
||
<!-- .element: class="fragment fade-in" -->
|
||
___
|
||
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## InSequence (1)
|
||
|
||
```C++
|
||
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"));
|
||
}
|
||
```
|
||
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.9em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## InSequence (2)
|
||
|
||
This has the same behaviour like previous example
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
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"));
|
||
}
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.9em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## InSequence - branch out
|
||
|
||
```C++
|
||
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);
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
+---> Method2 (seq1)
|
||
(seq1 seq2) |
|
||
Method1----|
|
||
|
|
||
+---> Method3 ---> Method4 (seq2)
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.9em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## mock non-virtual function (1)
|
||
|
||
We have the following class
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
struct Packet {};
|
||
|
||
class ConcretePacketStream {
|
||
public:
|
||
void AppendPacket(Packet* new_packet) {}
|
||
const Packet* GetPacket(size_t packet_number) const {}
|
||
size_t NumberOfPackets() const {}
|
||
};
|
||
```
|
||
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.9em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## mock non-virtual function (2)
|
||
|
||
We can create mock and instead of dynamic polymorphism use static polymorphism (templates)
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
// 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);
|
||
}
|
||
};
|
||
```
|
||
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.8em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## mock non-virtual function (3)
|
||
|
||
Now in test we can use mock class
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
TEST(TestNonVirtualMethod, ShouldTest) {
|
||
MockPacketStream mock_stream;
|
||
EXPECT_CALL(mock_stream, GetPacket).WillOnce(Return(nullptr));
|
||
|
||
PacketReader<MockPacketStream> reader;
|
||
reader.ReadPackets(&mock_stream, 12);
|
||
}
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
And in production code the real one
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
ConcretePacketStream stream;
|
||
PacketReader<ConcretePacketStream> reader;
|
||
|
||
auto* packet = reader.ReadPackets(&stream, 12);
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.9em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## StrictMock
|
||
|
||
The usage of `StrictMock` is similar to normal mock, except that it makes all uninteresting calls failures:
|
||
|
||
```C++
|
||
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());
|
||
}
|
||
```
|
||
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.9em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
|
||
## NiceMock
|
||
|
||
* <!-- .element: class="fragment fade-in" --> The usage of `StrictMock` is similar to normal mock, except that it reject uninteresting calls (we will not see them while run test)
|
||
* <!-- .element: class="fragment fade-in" --> 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)
|
||
|
||
```C++
|
||
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());
|
||
}
|
||
```
|
||
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.9em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## 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).
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
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.
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
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);
|
||
}
|
||
```
|
||
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.8em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## DoAll
|
||
|
||
If we need to combine a few actions, we can do this inside `doAll(...)`
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
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);
|
||
}
|
||
```
|
||
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.9em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## Invoke (1)
|
||
|
||
Let's change a little `MockBar`
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
class MockBar : public Bar {
|
||
public:
|
||
~MockBar() override = default;
|
||
MOCK_METHOD(bool, doOtherStuff, (const std::string&, int*, std::function<void(int)>), (const override));
|
||
};
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
Now we want to run callback. We can do this without capture it!
|
||
<!-- .element: class="fragment fade-in" -->
|
||
|
||
```C++
|
||
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)));
|
||
```
|
||
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.9em" -->
|
||
___
|
||
<!-- .slide: data-background="#ccc" -->
|
||
## Invoke (2)
|
||
|
||
```C++
|
||
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"));
|
||
}
|
||
```
|
||
<!-- .element: class="fragment fade-in" -->
|
||
<!-- .slide: style="font-size: 0.76em" -->
|
||
___
|
||
|
||
## 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`. |