Eats
Eats

Reputation: 607

Define and use MOCK_METHOD with gtest and gmock

I am new to googletest/googlemock and I have following questions:

First question: I have this DatabaseClient class which has a method query_items which I want to mock. I`m unable to find the syntax to do it. Here is my attempt:

class DatabaseClient {
  public:
    // constructors
    DatabaseClient();
    DatabaseClient(std::string base_url, std::string master_key);

    // destructor
    ~DatabaseClient();

    // properties
    some properties

    // methods
    // last parameter is optional with default value NULL
    CURLcode query_items(std::string databaseId, std::string containerId, std::string query, size_t (*p_callback_function)(void*, size_t, size_t, std::string*) = NULL);
};

class MockDatabaseClient {
    public:
        MOCK_METHOD(CURLcode, query_items, (std::string databaseId, std::string containerId, std::string query, size_t (*p_callback_function)(void*, size_t, size_t, std::string*));
        };

The MOCK_METHOD has compile errors, can you help in how to write it correctly?

SECOND Question: The Database client is used in a test service class which I want to test: Here is the sample of the method which I want to test:

#include "db/DatabaseClient.hpp"
#include "db/LibcurlCallbacks.hpp"

TestService::create() {
    DatabaseClient* databaseClient = new DatabaseClient();
    std::string body = "some query"
    try {
       auto respone = databaseClient->query_items(this->databaseName, this->containerName, body, \
            LibcurlCallbacks::CallbackFunctionOnCreate);

        return SomeObject;
    }

How can I mock the databaseClient->query_items in my test because I do not want to hit the database when running tests.

Here is the basic test I started:

#include <gtest/gtest.h>
#include "gmock/gmock.h" 

#include "../src/service/TestService.hpp"
#include "../src/db/DatabaseClient.hpp"
#include "../src/db/LibcurlCallbacks.hpp"


using ::testing::AtLeast;
TEST(HelloTest, BasicAssertions) {
  // Expect two strings not to be equal.
    MockCosmosClient cosmosClient;

    //EXPECT_CALL(cosmosClient, query_items("test", "test", "test", LibcurlCallbacks::CallbackFunctionOnDestinationCreate))

    TestService ds;
    auto response = ds.create();
  EXPECT_STRNE(response, "some string");

}

Any help is appreciated!

Upvotes: 2

Views: 8218

Answers (1)

Ari
Ari

Reputation: 7556

Somehow you need to tell your TestService class to use the mock object instead of the real object.

Currently you instantiate the DatabaseClient in create():

TestService::create() {
    DatabaseClient* databaseClient = new DatabaseClient();
    //...
    }

You should tell it to use MockDatabaseClient instead. This can be done in several ways:

Use dependency injection:

Create an abstract class interface called DatabaseClientInterface that has virtual functions, then have your MockDatabaseClient and DatabaseClient inherit and implement that class.

Then rather than instantiating databaseClient in TestService::create, have a member variable in TestService of type DatabaseClientInterface* which can be initialized in the constructor of TestService by an object of either MockDatabaseClient for testing or DatabaseClient for production.

In your test you should then call:

TEST(HelloTest, BasicAssertions) {
  MockDatabaseClient mock_client;
  TestService ds(&mock_client);
  //...

Templatize your class:

Make TestService a template class which creates the databaseClient object based on the template variable. Something like this:

template <typename T>
class TestService
{
 //...
 create() {
    T* databaseClient = new DatabaseClient();
    //...
    }

};

Now for testing instantiate TestService with MockDatabaseClient.

See GMock documentations or here for an example of the first method and here for an example of the second method.

Compile issues

As for the compile issues with MOCK_METHOD, note that macros are limited and the preprocessor gets confused by seeing , in a macro parameter. I think you are hitting this problem.

Upvotes: 2

Related Questions