I'm using the Given/When/Then pattern to make test code much clearer. Since I'm writing those tests in C++ I chosed to use Google Test. With tests the pattern is clear, because I do sth like this:
TEST(TestFixture, TestName)
{
// Given
int a = 5;
int b = 6;
int expectedResult = 30;
// When
int result = Multiply(a, b);
// Then
EXPECT_EQ(expectedResult, result);
}
But with mocks it stops being clear since there appear some EXPECTs in the Given part. The Given part suppose to be a setup step. Please see an example:
TEST(TestFixture, TestName)
{
// Given
int a = 5;
int b = 6;
int expectedResult = 30;
MightCalculatorMock mock;
EXPECT_CALL(mock, multiply(a,b))
.WillOnce(Return(expectedResult));
// When
int result = Multiply(mock, a, b);
// Then
EXPECT_EQ(expectedResult, result);
}
Is this approach correct? How the Given/When/Then comments should be placed in the test code, where?
Using the Turtle interface as example, here are the simple steps you need to follow: Derive a class MockTurtle from Turtle . Take a virtual function of Turtle (while it's possible to mock non-virtual methods using templates, it's much more involved). In the public: section of the child class, write MOCK_METHOD();
Only use a mock (or test double) “when testing things that cross the dependency inversion boundaries of the system” (per Bob Martin). If I truly need a test double, I go to the highest level in the class hierarchy diagram above that will get the job done. In other words, don't use a mock if a spy will do.
Google Test is a popular C++ unit testing framework developed by Google that can be used together with the closely related mocking extension framework, Google Mock, to test code that conforms to the SOLID principles for object-oriented software design.
EXPECT_CALL not only defines the behavior, but also sets an expectation that the method will be called with the given arguments, for the given number of times (and in the given order when you specify the order too).
The EXPECT_CALL
macro can be thought of as a way of testing interaction between a class and another class. As such, if you are using it with another EXPECT
macro, then your test is likely testing two things, which is why it appears to conflict with the "Given-When-Then" paradigm (also known as "Arrange-Act-Assert").
If you just need to set up some behavior on your mock object for testing, use the ON_CALL
macro instead:
TEST(TestFixture, TestName)
{
// Given
int a = 5;
int b = 6;
int expectedResult = 30;
MightCalculatorMock mock;
ON_CALL(mock, multiply(a,b))
.WillByDefault(Return(expectedResult));
// When
int result = Multiply(mock, a, b);
// Then
EXPECT_EQ(expectedResult, result);
}
If you are actually looking to test the iteraction between your system under test and some other collaborator, you can use an "Arrange-Expect-Act" pattern:
TEST(TestFixture, CalculatorIsCalledProperly)
{
// Arrange
int a = 5;
int b = 6;
int expectedResult = 30;
MightCalculatorMock mock;
// Expect
EXPECT_CALL(mock, multiply(Eq(a),Eq(b)));
// Act
int result = Multiply(mock, a, b);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With