GoogleMock: How to SetArgReferee according to another input parameter? - c++

I would like to use GoogleMock to mock a service as below:
class Request
{
int req_id;
int request;
};
class Response
{
int req_id;
int response;
};
int request(Response& res, const Request& req)
{
res.req_id = req.req_id;
res.response = 2 * req.request;
return 1;
}
EXPECT_CALL(mock_service, request(_,_)).WillOnce(DoAll(SetArgReferee<0>(/* what here? */), Return(1)));
How can I SetArgReferee for the Response& res according to the passed in const Request& req, i.e. res.req_id = req.req_id; and res.response = 2 * req.request; ?

Your code does not look like something that could be mocked - but I guess this is just illustration of the problem.
So assuming that you have mocked function reqest within mocked class MockService - then use Invoke Action with your request function as parameter:
EXPECT_CALL(mock_service, request(_,_)).WillOnce(Invoke(&request));
If you like to just call base class function - then do something like this:
class mock_service_class : public service_class
{
public:
MOCK_METHOD2(request, int(Response& res, const Request& req));
int baseRequest(Response& res, const Request& req)
{
return service_class::request(res, req);
}
};
And do your EXPECT_CALL in this way:
EXPECT_CALL(mock_service, request(_,_))
.WillOnce(Invoke(&mock_servide,
&mock_service_class::baseRequest));

Related

How do I mock this on C++?

FuncRes Test::test(HttpRequest& request, std::string& result) {
try {
auto httpClientSync = HttpClientSync::create(param);
HttpResponse response = httpClientSync->execute(request);
if (...) {
return FuncRes::SUCCESS;
} else if (...) {
return FuncRes::RETRY;
} else {
return FuncRes::FAILED;
}
} catch (...) {
return FuncRes::RETRY;
} catch (...) {
return FuncRes::FAILED;
}
}
httpClientSync is a local variable, it will destroy when the test is done.
I'm confused if I can mock HttpClientSync and "execute" method?
Refactor this function into 2 parts, one that creates real HttpClientSync, and one that accepts HttpClientSync interface:
FuncRes Test::test(HttpClientSync& httpClientSync, HttpRequest& request, std::string& result);
FuncRes Test::test(HttpRequest& request, std::string& result) {
auto httpClientSync = HttpClientSync::create(param);
test(httpClientSync, request, result);
}
Then test variant which accepts HttpClientSync in arguments, and pass mock instead of real client.
If you need to test some other code which calls this test function, and you still want to mock HttpClientSync, then instead of storing param in your Test class, store HttpClientSync& client instance, and pass it in constructor.

How to return a specific value every nth time of a consecutive call with Gmock

In the code Google Mock test snippet there is an EXPECT_CALL that returns True and an argument reference for 200 times.
How can I let the test only return True every nth time. For example return True each 10th call and otherwise return False.
class MockHandler : public Handler
{
public:
MOCK_METHOD1(RxMsg, bool(Msg &msg));
}
TEST(TestDispatcher, HandlePing)
{
auto mockedHandler = make_unique<MockHandler>();
Msg rxMsg = { REQUEST::REQ_PING, sizeof(DefaultMsg_t), rxMsg.rx,(uint8_t*)"0"};
EXPECT_CALL(*mockedHandler,
RxMsg(_)).Times(checkValue).WillRepeatedly(
DoAll(SetArgReferee<0>(rxMsg), Return(TRUE)));
Dispatcher dispatcher(10, mockedHandler);
for (int i = 0; i < 199; i++)
{
dispatcher.RunToCompletion();
}
}
There are few approaches that might work for you. I like the solution with Invoke as a default action, because it is the most flexible. You didn't provide mcve in your question, so I wrote very simple implementations for the classes you use. Also you made a mistake using unique_ptr for the mock. In 99% of cases is must be shared_ptr, because you are sharing it between testing environment and your System Under Test.
class Msg {};
class Handler {
public:
virtual bool RxMsg(Msg &msg) = 0;
};
class MockHandler: public Handler
{
public:
MOCK_METHOD1(RxMsg, bool(Msg &msg));
};
class Dispatcher {
public:
Dispatcher(std::shared_ptr<Handler> handler): h_(handler) {}
void run() {
Msg m;
std::cout << h_->RxMsg(m) << std::endl;
}
private:
std::shared_ptr<Handler> h_;
};
class MyFixture: public ::testing::Test {
protected:
MyFixture(): mockCallCounter_(0) {
mockHandler_.reset(new MockHandler);
sut_.reset(new Dispatcher(mockHandler_));
}
void configureMock(int period) {
ON_CALL(*mockHandler_, RxMsg(_)).WillByDefault(Invoke(
[this, period](Msg &msg) {
// you can also set the output arg here
// msg = something;
if ((mockCallCounter_++ % period) == 0) {
return true;
}
return false;
}));
}
int mockCallCounter_;
std::shared_ptr<MockHandler> mockHandler_;
std::unique_ptr<Dispatcher> sut_;
};
TEST_F(MyFixture, HandlePing) {
configureMock(10);
for (int i = 0; i < 199; i++) {
sut_->run();
}
}
At the beginning of each test you should call configureMock method that will Invoke ON_CALL macro setting the default action for your mock. Function passed to Invoke can be any function matching the signature of the method you are overwriting. In this case it;s a function that counts how many times mock has already been called and returns appropriate value. You can also assign some particular object to the msg output argument.

Gmock object not being passed correctly into async function

I am trying to mock parts of the AWS SDK in C++ for testing. Specifically, I'm mocking a KMSClient and DecryptOutcome object. The MockKMSClient is set to pass in a MockDecryptOutcome into the DecryptResponseReceivedHandler.
Here are my mocked classes:
class MockDecryptOutcome : public Aws::KMS::Model::DecryptOutcome {
public:
Aws::Utils::Base64::Base64 _Base64;
MockDecryptOutcome(string request) {
if (request == SUCCESS) {
EXPECT_CALL(*this, IsSuccess()).WillRepeatedly(Return(true));
Aws::KMS::Model::DecryptResult result;
result.SetPlaintext(_Base64.Decode(SUCCESS));
EXPECT_CALL(*this, GetResult()).WillRepeatedly(Return(result));
} else {
EXPECT_CALL(*this, IsSuccess()).WillRepeatedly(Return(false));
if (request == GRANT_TOKEN_NEEDED) {
EXPECT_CALL(*this, GetError()).WillRepeatedly(Return(Aws::KMS::KMSErrors::ACCESS_DENIED));
} else if (request == ENDPOINT_ERROR) {
EXPECT_CALL(*this, GetError()).WillRepeatedly(Return(Aws::KMS::KMSErrors::NETWORK_CONNECTION));
}
}
}
virtual ~MockDecryptOutcome() {};
MOCK_METHOD0(IsSuccess, bool());
MOCK_METHOD0(GetResult, Aws::KMS::Model::DecryptResult());
MOCK_CONST_METHOD0(GetError, Aws::KMS::KMSErrors());
};
class MockKMSClient : public Aws::KMS::KMSClient {
public:
MockKMSClient() {
EXPECT_CALL(*this, DecryptAsync_impl(_, _)).WillRepeatedly(Invoke(this, &MockKMSClient::do_DecryptAsync));
}
virtual ~MockKMSClient() {};
Aws::Utils::Base64::Base64 _Base64;
// Have to invoke Mocked method manually to discard optional parameter
void DecryptAsync(
const Aws::KMS::Model::DecryptRequest& request,
const Aws::KMS::DecryptResponseReceivedHandler& handler,
const std::shared_ptr<const Aws::Client::AsyncCallerContext>& context = nullptr
) const
{
DecryptAsync_impl(request, handler);
}
MOCK_CONST_METHOD2(
DecryptAsync_impl,
void(
const Aws::KMS::Model::DecryptRequest& request,
const Aws::KMS::DecryptResponseReceivedHandler& handler
)
);
void do_DecryptAsync(
const Aws::KMS::Model::DecryptRequest& request,
const Aws::KMS::DecryptResponseReceivedHandler& handler
)
{
const MockDecryptOutcome& outcome(_Base64.Encode(request.GetCiphertextBlob()));
cout << &outcome << endl;
handler(this, request, outcome, nullptr);
}
};
The handler is defined in the AWS SDK here: http://sdk.amazonaws.com/cpp/api/LATEST/namespace_aws_1_1_k_m_s.html#a6bb4999b2fbc6cd499913779e42421b3
Here is the callback function:
void KmsCallback::on_decrypt_callback(
const Aws::KMS::KMSClient* client,
const Aws::KMS::Model::DecryptRequest&,
const Aws::KMS::Model::DecryptOutcome& outcome,
const std::shared_ptr<const Aws::Client::AsyncCallerContext>&
)
{
cout << &outcome << endl;
}
Finally, here is where the async function is called:
kms_client->DecryptAsync(
decrypt_request,
std::bind(
&KmsCallback::on_decrypt_callback,
this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4
)
);
Running this in a test prints out two different memory addresses for the DecryptOutcome variables:
0x7f03b6064dc0
0x7f03b6064dc8
I've tried using the "new" operator, removing "const", and many other combinations to get this to work without success. Any suggestions would be appreciated.

Passing c++ lambda to C functions

I am trying to wrap a C++ layer over libuv, and using lambda for callback functions. However gcc is erroring out.
Here is the minified version:
#include <uv.h>
class Test {
public:
void on_conn(uv_stream_t *server, int status) { }
void test() {
uv_tcp_t server;
auto err = uv_listen((uv_stream_t*)&server,
100,
[this] (uv_stream_s *server, int status) -> void {
this->on_conn(server,status);
});
}
};
Test t;
The relevant declarations in libuv are:
# define UV_EXTERN /* nothing */
struct uv_stream_s { ... };
typedef struct uv_stream_s uv_stream_t;
typedef void (*uv_connection_cb)(uv_stream_t* server, int status);
UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
The error g++ is giving:
$ g++ --version
g++ (GCC) 6.1.1 20160501
<<--ERROR--{reformatted}-->>
t.cpp:15:7: error: cannot convert
‘Test::test()::<lambda(uv_stream_s*, int)>’ to
‘uv_connection_cb {aka void (*)(uv_stream_s*, int)}’
for argument ‘3’ to ‘int uv_listen(uv_stream_t*, int, uv_connection_cb)’
}));
What exactly is broken here ? Any way to make this work ?
UPDATE:
More fun .. this in body of lambda does something ; first call works, second doesn't.
int cfunc( void cb() );
class Test {
public:
void d(){}
void test() {
cfunc( [=] () {});
cfunc( [=] () { this->d(); });
//cfunc( [this] () { });
//cfunc( [&this] () { });
}
};
t.cpp:10:34: error: cannot convert ‘Test::test()::<lambda()>’ to ‘void (*)()’ for argument ‘1’ to ‘int cfunc(void (*)())’
cfunc( [=] () { this->d(); });
A capturing lambda cannot be converted to a function pointer, only a non-capturing can:
//Lambda captures 'this', and so cannot be converted to function pointer
[this](uv_stream_s *server, int status) -> void {
this->on_conn(server,status);
}
Maybe you can use a trick like the following one:
class Test;
struct my_uv_tcp_t: uv_tcp_t {
Test *test;
};
class Test {
public:
Test(): server{} { server.test = this; }
void on_conn(uv_stream_t *server, int status) { }
static void cb(uv_stream_t *server, int status) {
auto srv = static_cast<my_uv_tcp_t*>(server);
srv->test->on_conn(server, status);
}
void test() {
auto err = uv_listen((uv_stream_t*)&server, 100, Test::cb);
}
private:
my_uv_tcp_t server;
};
The stream is given back once something happens on it and the handle of it is nothing more than a naked pointer.
You can use that same stream to store the information of the controller (the instance of the Test class in your case) and cast the stream to its original form when you receive it.
Otherwise, use the data field that is part of the handle if it's still unused.
It should be work. I had same problem, so I sent current object to lambda over handle object property.
#include <uv.h>
class Test {
public:
void on_conn(uv_stream_t *server, int status) { }
void test() {
uv_tcp_t server;
server.data = this;
auto err = uv_listen((uv_stream_t*)&server,
100,
[] (uv_stream_s *server, int status) -> void {
auto self = (Test*)server->data;
self->on_conn(server,status);
});
}
};
Test t;

How to generate BlockingStub in C++ in Protobuf?

I'm having the following .proto for Protobuf (2.6.1 to be more detailed):
service InstallService {
rpc getWifiNetworks (WifiRequest) returns (WifiResponse);
}
I've generated java files and i'm having BlockingStub:
TestInstallService.BlockingInterface service = TestInstallService.newBlockingStub(channel);
and i can use if in blocking way (works good):
Wifi.WifiResponse response = service.getWifiNetworks(controller, request);
Now i'm creating C++ client which should work in blocking way too but i can't see any Blocking interfaces neither in proto nor in generated C++ code. How to generate BlockingStub in C++ in Protobuf? How can i pass closure if working in async way?
Generated C++ service file (.cpp):
class InstallService_Stub;
class InstallService : public ::google::protobuf::Service {
protected:
// This class should be treated as an abstract interface.
inline InstallService() {};
public:
virtual ~InstallService();
typedef InstallService_Stub Stub;
static const ::google::protobuf::ServiceDescriptor* descriptor();
virtual void getWifiNetworks(::google::protobuf::RpcController* controller,
const ::WifiRequest* request,
::WifiResponse* response,
::google::protobuf::Closure* done);
// implements Service ----------------------------------------------
const ::google::protobuf::ServiceDescriptor* GetDescriptor();
void CallMethod(const ::google::protobuf::MethodDescriptor* method,
::google::protobuf::RpcController* controller,
const ::google::protobuf::Message* request,
::google::protobuf::Message* response,
::google::protobuf::Closure* done);
const ::google::protobuf::Message& GetRequestPrototype(
const ::google::protobuf::MethodDescriptor* method) const;
const ::google::protobuf::Message& GetResponsePrototype(
const ::google::protobuf::MethodDescriptor* method) const;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InstallService);
};
class InstallService_Stub : public InstallService {
public:
InstallService_Stub(::google::protobuf::RpcChannel* channel);
InstallService_Stub(::google::protobuf::RpcChannel* channel,
::google::protobuf::Service::ChannelOwnership ownership);
~InstallService_Stub();
inline ::google::protobuf::RpcChannel* channel() { return channel_; }
// implements InstallService ------------------------------------------
void getWifiNetworks(::google::protobuf::RpcController* controller,
const ::WifiRequest* request,
::WifiResponse* response,
::google::protobuf::Closure* done);
private:
::google::protobuf::RpcChannel* channel_;
bool owns_channel_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InstallService_Stub);
};
It seems that no blocking code is generated by protoc so i had to use self-made blocking:
bool callbackFired = false;
void myCallback() {
// ...
callbackFired = true;
}
// run service method
service->myMethod(rpcController, request, response, NewCallback(&myCallback));
// block the thread until callback is invoked
while (!callbackFired);
...
C++ client usage example: https://github.com/4ntoine/protobuf-socket-rpc
The way you do this is to provide your own subclass of InstallService that overrides the methods you want to implement:
struct MyInstallService : public InstallService
{
void getWifiNetworks(::google::protobuf::RpcController* controller,
const ::WifiRequest* request,
::WifiResponse* response,
::google::protobuf::Closure* done) override
{
// do your work here
// fill up the response here
done->Run(); // this will trigger the response
}
};
client side:
Something like this
namespace detail {
template<class F>
struct simple_closure : google::protobuf::Closure {
simple_closure(F f)
: _f(std::move(f))
{}
void Run() override {
_f();
}
private:
F _f;
};
}
template<class F>
std::unique_ptr<detail::simple_closure<F>> make_closure(F&& f) {
return std::make_unique<detail::simple_closure<F>>(std::forward<F>(f));
}
std::unique_ptr<WifiResponse> syncGetWifiNetworks(InstallService_Stub & stub, const WifiRequest& req)
{
auto result = std::make_unique<WifiResponse>();
auto promise = std::promise<std::unique_ptr<WifiResponse>>;
auto future = promise.get_future();
auto controller = allocate_controller(); // you need to write this
auto closure = make_closure([&result, &promise]{
promise.set_value(std::move(result));
});
// assumes you already have an async comms queue - otherwise just
// dispatch this lambda to a std::async(std::launch::async, ...)
comms_queue.dispatch([&controller, &req, &stub, &response]{
stub.getWifiNetworks(controller, &req, response.get(), closure);
};
// HERE is where the current thread blocks until the promise is fulfilled
return future.get();
}