mirror of
https://github.com/google/googletest.git
synced 2025-03-28 06:58:20 +00:00
78 lines
3.2 KiB
Markdown
78 lines
3.2 KiB
Markdown
|
#### Testing Code that Uses a Stubby Server
|
||
|
|
||
|
(Contributed by JonWray on 2008/3/11; updated by ZhanyongWan later.)
|
||
|
|
||
|
I'm testing a C++ frontend that calls several different backends, but I'll just
|
||
|
include an example for one to keep this relatively short. This example is
|
||
|
mocking a `CacheServer` backend. An explanation follows the code.
|
||
|
|
||
|
```cpp
|
||
|
using ::testing::_;
|
||
|
using ::testing::BeDone;
|
||
|
using ::testing::EqualsProto;
|
||
|
using ::testing::RespondWith;
|
||
|
|
||
|
class MockCacheServer : public CacheServerRPC {
|
||
|
public:
|
||
|
MockCacheServer(HTTPServer *hs) {
|
||
|
rpc2::EnableRPC2(this, rpc2::ServiceParameters());
|
||
|
CacheServerRPC::ExportService(hs);
|
||
|
ON_CALL(*this, Insert).WillByDefault(BeDone());
|
||
|
ON_CALL(*this, Lookup).WillByDefault(BeDone());
|
||
|
}
|
||
|
|
||
|
MOCK_METHOD(void, Insert,
|
||
|
(RPC*, const CacheInsertCommandProto*, CacheInsertResultsProto*,
|
||
|
Closure*),
|
||
|
(override));
|
||
|
MOCK_METHOD(void, Lookup,
|
||
|
(RPC*, const CacheLookupCommandProto*, CacheLookupResultsProto*,
|
||
|
Closure*),
|
||
|
(override));
|
||
|
};
|
||
|
...
|
||
|
// This is in the test fixture.
|
||
|
MockCacheServer cacheserver_;
|
||
|
...
|
||
|
// Now the code that uses it:
|
||
|
CacheLookupCommandProto command;
|
||
|
// Init command
|
||
|
CacheLookupResultsProto results;
|
||
|
// Init results
|
||
|
|
||
|
EXPECT_CALL(cacheserver_, Lookup(_, EqualsProto(command), _, _))
|
||
|
.WillOnce(RespondWith(results));
|
||
|
```
|
||
|
|
||
|
In the success case, the command matches the `EXPECT_CALL`, so results is set
|
||
|
and the callback is called.
|
||
|
|
||
|
In the failure case, the command matches the default `ON_CALL`, the results are
|
||
|
not set, and the done closure is called (don't want the test to hang).
|
||
|
|
||
|
So it's a bit ugly, but given that I need to mock five backends, I think it's
|
||
|
better than doing this manually. The best part is the nicely formatted error
|
||
|
messages when the expected call is incorrect. Once all this scaffolding is in
|
||
|
place, it's easy to churn out test suites.
|
||
|
|
||
|
**Discussions:**
|
||
|
|
||
|
* ZhanyongWan: `StubbySimulator` by Mike Bland might also be useful:
|
||
|
google3/testing/lib/net/rpc/stubby_simulator.h.
|
||
|
* JonWray: This is turning a mock into a fake, isn't it? All requests are
|
||
|
accepted, and you can write logic to set the reply conditionally on the
|
||
|
request. The interesting thing is the logic moves from the mock class into
|
||
|
the test suite.
|
||
|
* MikeBland: It's sort of a Frankenstein, but it works well for my purposes.
|
||
|
It collaborates with a mock Stubby server, which sets the expectation and
|
||
|
does the actual intercepting of the args, and then gives you the freedom to
|
||
|
fiddle with the results while the RPC is conceptually "in flight". This is
|
||
|
especially handy for "pausing" the RPC and having it return a state other
|
||
|
than `RPC::OK`. This sort of approach to splitting RPC calls into separate
|
||
|
objects from ControlFlows was first explored in
|
||
|
[TotT Episode 46](http://tott/2007/06/episode-46-encapsulated-rpcs-or.html).
|
||
|
* PiotrKaminski: The [Service Mocker](http://go/servicemocker) is a gMock-like
|
||
|
framework that specializes in mocking Stubby services. It allows for small,
|
||
|
in-process tests, doesn't require manually writing a service mock, and can
|
||
|
deal with async clients, streaming and testing for cancellations.
|