Using Mock Tools

Mock tools such as Google Mock, CppUMock, or Hippo Mocks simplify your effort to define mocks and set up expectations. You’ll learn how to use Google Mock in this section.

Defining a Derivative

Let’s test-drive summaryDescription again. We’ll need to mock the HTTP methods get and initialize.

c5/7/Http.h
 
virtual​ ~Http() {}
 
virtual​ ​void​ initialize() = 0;
 
virtual​ std::​string​ get(​const​ std::​string​& url) ​const​ = 0;

The first step in using the mock support built into Google Mock is to create a derived class that declares mock methods. Google Mock allows us to define the HttpStub derivative succinctly.

c5/7/PlaceDescriptionServiceTest.cpp
 
class​ HttpStub: ​public​ Http {
 
public​:
*
MOCK_METHOD0(initialize, ​void​());
*
MOCK_CONST_METHOD1(get, ​string​(​const​ ​string​&));
 
};

To declare a mock method, you use one of a few macro forms. MOCK_CONST_METHOD1 tells Google Mock to define a const member function taking one argument (that’s the 1 at the end of MOCK_CONST_METHOD1). The first macro argument, get, represents the name of the member function. You supply the rest of the member function’s signature—its return value and argument declarations—as the second macro argument (string(const string&)).

To mock initialize, you use MOCK_METHOD0, which creates a nonconst, zero-argument override. The second macro argument, void(), says to declare a function that takes no arguments and returns void.

Google Mock also provides support for mocking template functions and for specifying the calling convention.[20]

Google Mock translates a mock declaration into a member function defined on the derived class. Behind the scenes, Google Mock synthesizes an implementation for that function to manage interactions with it. If the member function doesn’t override the appropriate base class function, you won’t get the behavior you want.

(Under C++11, the override keyword lets the compiler verify that you’ve properly overridden a function. However, the MOCK_METHOD macros don’t yet accommodate the override keyword. See https://code.google.com/p/googlemock/issues/detail?id=157 for a patch that you can apply to Google Mock to fix this shortfall.)

Setting Expectations

We decide to delete our implementation of summaryDescription and test-drive it again. We choose to shrink the scope of the first test. Instead of driving an implementation for all of summaryDescription, we’ll drive in only the code that sends off an HTTP request. A new test name captures our intent.

c5/7/PlaceDescriptionServiceTest.cpp
 
TEST_F(APlaceDescriptionService, MakesHttpRequestToObtainAddress) {
 
HttpStub httpStub;
 
string​ urlStart{
 
"http://open.mapquestapi.com/nominatim/v1/reverse?format=json&"​};
 
auto​ expectedURL = urlStart +
 
"lat="​ + APlaceDescriptionService::ValidLatitude + ​"&"​ +
 
"lon="​ + APlaceDescriptionService::ValidLongitude;
*
EXPECT_CALL(httpStub, get(expectedURL));
 
PlaceDescriptionService service{&httpStub};
 
 
service.summaryDescription(ValidLatitude, ValidLongitude);
 
}

We use the EXPECT_CALL macro to set up expectations as part of the test’s Arrange step (see Arrange-Act-Assert/Given-When-Then). The macro configures Google Mock to verify that a message get gets sent to the httpStub object with an argument that matches expectedURL.

Where’s the assertion? Google Mock does its verification when the mock object goes out of scope. Visually, our test doesn’t follow AAA, but the assertion step still executes—it just does so implicitly. Some mock tools require you to add an explicit verification call, which would once again make your assert step visible.

If needed, you can force Google Mock to run its verification before the mock goes out of scope.

 
Mock::VerifyAndClearExpectations(&httpStub);

Seeing an explicit assert step might make some folks happy, but it’s not necessary. You’ll quickly learn how to read a test when you see mock expectations being set.

We implement just enough of summaryDescription to compile.

c5/7/PlaceDescriptionService.cpp
 
string​ PlaceDescriptionService::summaryDescription(
 
const​ ​string​& latitude, ​const​ ​string​& longitude) ​const​ {
 
return​ ​""​;
 
}

Running our tests produces the following failure:

 
Actual function call count doesn't match EXPECT_CALL(httpStub, get(expectedURL))...
 
Expected: to be called once
 
Actual: never called - unsatisfied and active

The expectation was not met. No code called get on httpStub by the time our test completed. That’s a good failure! We implement enough code to pass the test.

c5/8/PlaceDescriptionService.cpp
 
string​ PlaceDescriptionService::summaryDescription(
 
const​ ​string​& latitude, ​const​ ​string​& longitude) ​const​ {
 
string​ server{​"http://open.mapquestapi.com/"​};
 
string​ document{​"nominatim/v1/reverse"​};
 
string​ url = server + document + ​"?"​ +
 
keyValue(​"format"​, ​"json"​) + ​"&"​ +
 
keyValue(​"lat"​, latitude) + ​"&"​ +
 
keyValue(​"lon"​, longitude);
 
http_->get(url);
 
return​ ​""​;
 
}

We write a second test to flesh out summaryDescription.

c5/9/PlaceDescriptionServiceTest.cpp
 
TEST_F(APlaceDescriptionService, FormatsRetrievedAddressIntoSummaryDescription) {
 
HttpStub httpStub;
*
EXPECT_CALL(httpStub, get(_))
*
.WillOnce(Return(
*
R​"({ "​address​": {
*
"​road​":"​Drury Ln​",
*
"​city​":"​Fountain​",
*
"​state​":"​CO​",
*
"​country​":"​US​" }})"​));
 
PlaceDescriptionService service(&httpStub);
 
auto​ description = service.summaryDescription(ValidLatitude, ValidLongitude);
 
ASSERT_THAT(description, Eq(​"Drury Ln, Fountain, CO, US"​));
 
}

The EXPECT_CALL invocation in the test tells Google Mock what to return from a call to get. To paraphrase the code, a call on the HttpStub object to get will once (and only once) return a specific JSON string value.

We don’t care what gets passed in the get call, since we verified that behavior in MakesHttpRequestToObtainAddress. Our EXPECT_CALL uses the wildcard matcher _ (an underscore; its qualified name is testing::_) as an argument to get. The wildcard allows Google Mock to match on any call to the function, regardless of the argument.

The wildcard increases the test’s level of abstraction by removing an irrelevant detail. However, the lack of concern over the URL argument means that we’d better have that other test (MakesHttpRequestToObtainAddress) that is concerned with proper argument passing. In other words, don’t use wildcard matchers unless you truly don’t care about the arguments or if you already have other tests that do care.

(The wildcard is one of many matchers provided by Google Mock. The matchers are the same ones you’ve been using for your assertions. See the Google Mock documentation[21] for the full list of matchers.)

We get the test to pass.

c5/9/PlaceDescriptionService.cpp
 
string​ PlaceDescriptionService::summaryDescription(
 
const​ ​string​& latitude, ​const​ ​string​& longitude) ​const​ {
 
string​ server{​"http://open.mapquestapi.com/"​};
 
string​ document{​"nominatim/v1/reverse"​};
 
string​ url = server + document + ​"?"​ +
 
keyValue(​"format"​, ​"json"​) + ​"&"​ +
 
keyValue(​"lat"​, latitude) + ​"&"​ +
 
keyValue(​"lon"​, longitude);
*
auto​ response = http_->get(url);
 
*
AddressExtractor extractor;
*
auto​ address = extractor.addressFrom(response);
*
return​ address.summaryDescription();
 
}

We can refactor to the same implementation as when we test-drove using a hand-crafted mock (see code/c5/10 in the source distribution).

Nice Mocks and Strict Mocks

Astute readers may have noted that we don’t follow the proper CurlHttp protocol in our implementations of summaryDescription. We don’t call initialize before calling get. (Don’t forget to run your integration tests!) To drive in a call to initialize, we can add an expectation to the MakesHttpRequestToObtainAddress test.

c5/11/PlaceDescriptionServiceTest.cpp
 
TEST_F(APlaceDescriptionService, MakesHttpRequestToObtainAddress) {
 
HttpStub httpStub;
 
string​ urlStart{
 
"http://open.mapquestapi.com/nominatim/v1/reverse?format=json&"​};
 
auto​ expectedURL = urlStart +
 
"lat="​ + APlaceDescriptionService::ValidLatitude + ​"&"​ +
 
"lon="​ + APlaceDescriptionService::ValidLongitude;
*
EXPECT_CALL(httpStub, initialize());
 
EXPECT_CALL(httpStub, get(expectedURL));
 
PlaceDescriptionService service{&httpStub};
 
 
service.summaryDescription(ValidLatitude, ValidLongitude);
 
}

The high-level policy in summaryDescription remains untouched. We make an isolated change to get to update its implementation detail.

c5/11/PlaceDescriptionService.cpp
 
string​ PlaceDescriptionService::get(​const​ ​string​& url) ​const​ {
*
http_->initialize();
 
return​ http_->get(url);
 
}

When we run the tests, we receive a warning—not for MakesHttpRequestToObtainAddress but for FormatsRetrievedAddressIntoSummaryDescription, which is the other test.

 
GMOCK WARNING:
 
Uninteresting mock function call - returning directly.
 
function call: initialize()

Google Mock captures all interactions with a mock object, not just the ones for which you set expectations. The warning is intended to help by telling you about an interaction you might not have expected.

Your goal should always be zero warnings. Either turn them all off or fix them as soon as they arise. Any other strategy that allows warnings to stick around will breed hundreds or thousands of warnings over time. At that point, they’re all pretty much useless. Ignoring the Google Mock warning is unacceptable; we must eliminate it.

We have other choices. We could add the expectation to FormatsRetrievedAddressIntoSummaryDescription, but that adds a bit of clutter to the test that has nothing to do with its goal. We’ll avoid this solution that goes against the concept of test abstraction.

Always question design when you’re presented with a challenge like this. The initialization call is required, but does it belong elsewhere (perhaps in an initialization function called after construction of PlaceDescriptionService)? Moving the call to a different place wouldn’t eliminate the warning, though.

What about the test design? We split one test into two when we changed from a hand-rolled mock solution to one using Google Mock. If we expressed everything in a single test, that one test could set up the expectations to cover all three significant events (initialization, message passing to get, and return from get). That’s an easy fix, but we’d end up with a cluttered test. See One Assert per Test for further discussion about this choice. For now, let’s stick with separate tests.

We could also create a fixture helper function that added the expectation on initialize and then returned the HttpStub instance. We might name such a function createHttpStubExpectingInitialization.

Google Mock provides a simpler solution (and many other mock tools provide similar solutions). The NiceMock template effectively tells Google Mock to track interactions only for methods on which expectations exist.

c5/12/PlaceDescriptionServiceTest.cpp
 
TEST_F(APlaceDescriptionService, FormatsRetrievedAddressIntoSummaryDescription) {
*
NiceMock<HttpStub> httpStub;
 
EXPECT_CALL(httpStub, get(_))
 
.WillOnce(Return(
 
// ...
 
}

In contrast, wrapping a mock in StrictMock turns the uninteresting mock call warning into an error.

 
StrictMock<HttpStub> httpStub;

By using NiceMock, we take on a small risk. If the code later somehow changes to invoke another method on the Http interface, our tests aren’t going to know about it. You should use NiceMock when you need it, not habitually. Seek to fix your design if you seem to require it often.

You can read more about NiceMock and StrictMock in the Google Mock documentation.[22]

Order in the Mock

It’s unlikely, but what if we inadvertently swapped the order of the calls to Http’s initialize and get functions?

c5/13/PlaceDescriptionService.cpp
 
string​ PlaceDescriptionService::get(​const​ ​string​& url) ​const​ {
*
auto​ response = http_->get(url);
*
http_->initialize();
*
return​ response;
 
}

Surprise, the tests still pass! By default, Google Mock doesn’t concern itself with verifying the order in which expectations are met. If you’re concerned about order, you can tell Google Mock (and many other C++ mocking tools) to verify it. The simplest way is to declare an instance of InSequence at the top of the test and ensure that subsequent EXPECT_CALLs appear in the order you expect.

c5/13/PlaceDescriptionServiceTest.cpp
 
TEST_F(APlaceDescriptionService, MakesHttpRequestToObtainAddress) {
*
InSequence forceExpectationOrder;
 
HttpStub httpStub;
 
 
string​ urlStart{
 
"http://open.mapquestapi.com/nominatim/v1/reverse?format=json&"​};
 
 
auto​ expectedURL = urlStart +
 
"lat="​ + APlaceDescriptionService::ValidLatitude + ​"&"​ +
 
"lon="​ + APlaceDescriptionService::ValidLongitude;
 
EXPECT_CALL(httpStub, initialize());
 
EXPECT_CALL(httpStub, get(expectedURL));
 
PlaceDescriptionService service{&httpStub};
 
 
service.summaryDescription(ValidLatitude, ValidLongitude);
 
}

Google Mock provides finer control over order if you require it. The After clause says that an expectation is met only if it executes after another expectation. Google Mock also lets you define an ordered list of expected calls. Refer to the Google Mock documentation[23] for further information.

Making a Mockery of Things: Clever Mock Tool Features

The EXPECT_CALL macro supports a number of additional modifiers. Here’s its syntax:

 
EXPECT_CALL(mock_object, method(matchers))
 
.With(multi_argument_matcher) ?
 
.Times(cardinality) ?
 
.InSequence(sequences) *
 
.After(expectations) *
 
.WillOnce(action) *
 
.WillRepeatedly(action) ?
 
.RetiresOnSaturation(); ?

(The ? and * represent the cardinality of each modifier: ? indicates that you can optionally call the modifier once, and * indicates that you can call the modifier any number of times.)

The most likely useful modifier is Times, which lets you specify the exact number of times you expect a method to be called. You can specify WillRepeatedly if you know a method will be called many times but aren’t concerned with exactly how many. Refer to the Google Mock documentation[24] for further nuances and details.

Google Mock is a general-purpose unit testing tool that supports mocking for just about any convolution that you can code. For example, suppose you need to mock a function to populate an out parameter. Yup, Google Mock can do that. The following interface, defined on a class named DifficultCollaborator, represents a function that both returns a value and populates an argument:

c5/13/OutParameterTest.cpp
 
virtual​ ​bool​ calculate(​int​* result)

You can specify one action for a Google Mock expectation, using either WillOnce or WillRepeatedly. Most of the time, that action will be to return a value. In the case of a function that needs to do more, you can use DoAll, which creates a composite action from two or more actions.

c5/13/OutParameterTest.cpp
 
DifficultCollaboratorMock difficult;
 
Target calc;
 
EXPECT_CALL(difficult, calculate(_))
*
.WillOnce(DoAll(
*
SetArgPointee<0>(3),
*
Return(true)));
 
 
auto​ result = calc.execute(&difficult);
 
 
ASSERT_THAT(result, Eq(3));

Our additional action for this example is SetArgPointee<0>(3), which tells Google Mock to set the pointee (the thing that’s getting pointed at) for the 0th argument to the value 3.

Google Mock has solid support for other side-effect actions, including the ability to throw exceptions, set variable values, delete arguments, and invoke functions or functors. Refer to the Google Mock documentation[25] for the complete list.

Just because you can doesn’t necessarily mean you should, though. Most of the time, the basic Google Mock mechanisms you learned earlier will suffice. When test-driving, if you find yourself seeking esoteric mock tool features frequently, stop and take a look at your design. Are you testing a method that’s doing too much? Can you restructure your design in a manner so that you don’t need such complex mocking? More often than not, you can.

Where you may need the more powerful features of your mock tool is when you tackle the challenge of writing tests around non-test-driven, poorly structured code. You’ll learn about these challenges in Chapter 8, Legacy Challenges.

Troubleshooting Mock Failures

You will invariably struggle with defining mocks properly. I’ll come clean: in coding our current example for this book, I scratched my head for several minutes when I received the following failure message:

 
Actual function call count doesn't match EXPECT_CALL(httpStub, get(expectedURL))...
 
Expected: to be called once
 
Actual: never called - unsatisfied and active

The first thing to determine is whether the production code actually makes the proper call. (Have you even coded anything yet?) Second, have you defined the mock method properly? If you’re not sure, you either can add a cout statement as the first line of the production implementation or can crank up the debugger.

Did you make the member function getting mocked virtual?

Did you botch the MOCK_METHOD declaration? All type information must match precisely; otherwise, the mock method is not an override. Ensure all const declarations match.

If you’re still stuck, eliminate any concerns about argument matching. Use the wildcard matcher (testing::_) for all arguments and rerun the tests. If they pass, then one of the arguments is not recognized as a match by Google Mock.

My stupidity was that I had inadvertently stripped the const declaration from the URL argument.

One Test or Two?

When using a handcrafted mock, we ended up with a single test to verify the true end goal, the ability to generate a summary description for a location. In the second example, however, we ended up with two tests. Which is right?

From the stance of documenting public behaviors—those a client would care about—PlaceDescriptionService’s sole goal is to return a summary string given a location. Describing this behavior in a single test might be simpler for a reader. The interaction of summaryDescription with its Http collaborator isn’t of interest to the client. It’s an implementation detail (you might imagine a solution where we have all the geolocation data locally). Does it make sense to create a second test to document that interaction?

Absolutely. TDD’s most important value is in helping you drive and shape the design of your system. Interactions with collaborators are a key aspect of that design. Having tests that describe those interactions will be of high value to other developers.

Having two tests provides additional benefits. First, a mock verification is an assertion. We already require an assertion to verify the summary string. Splitting into two tests falls in line with one assert per test (One Assert per Test). Second, the separated tests are eminently more readable. Setting expectations in Google Mock makes it harder to spot the assertion points (and also to keep in line with Arrange-Act-Assert/Given-When-Then), so anything we can do to simplify mock-based tests pays off.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.200.220