ghostrider
ghostrider

Reputation: 5259

C++ Google mock/unit tests : Mock method not called and original one is

I am mocking a method but it seems that my GoogleTest keeps calling the original implementation. Probably missing something but can't find out what is this?

My class is a Postgres database accessor:

namespace project
{

class PostgresDb
{
public :
    // typedef the CursorPtr, this is just a smart pointer.
    // sth like 
    typedef shared_ptr<DbDataType> CursorPtr ;

    PostgresDb( const std::string & connString ) ;

    CursorPtr getRecords( const int id_1 ,
                          const int id_2 ) ;

protected :

    // this will be used by the MockPostgresDb in our unit tests.
    // it leaves the object uninitialized
     PostgresDb (){} ;

 }

}// end of namespace

and here is my mock class:

namespace project_test
{

class MockPostgresDb : public project::PostgresDb
{
public :
    MockPostgresDb(){} ;
    MOCK_METHOD2( getRecords, CursorPtr*( const int , const int  ) ) ;
} ;

class MockCursor : public CursorPtr
{
    // ....
}

}

and here is the method I am testing and the test:

void original_get_method( const int id_1, const int id_2 , PostgresDb db)
{
    // ....
    db.getRecords( id_1, id_2 ) ;
    // ....
}

// helper function
setupGetRecords( MockPostgresDb* db     ,
                 MockCursor*     cursor ) 
{
    EXPECT_CALL( *db, getRecords(_,_) )
        .Times( 1 )
        .WillRepeatedly(::testing::Return( cursor ) ) ;
}


TEST_F(....)
{
    MockPostgresDb db ;
    MockCursor     cursor ;
    // ....
    setupGetRecords( &db, &cursor ) ; 
    // ....
    // and then calling a functi
    original_method( id_1, id_2, db ) ;
}

So in my mind, I am calling original_method and pass a mock_db. The mock_db calls its method getRecords which returns a MockCursor. This is where it should get me the mock one but I do enter the db::getRecords.

I am trying to find where the mismatch is but cannot figure out.

EDIT :

So, as pointed out - getRecords should return a CursorPtr and not a CursorPtr*. So here is what I did:

I also tried to change

MOCK_METHOD2( getRecords, CursorPtr*( const int , const int  ) ) ;`

to

MOCK_METHOD2( getRecords, CursorPtr( const int , const int  ) ) ;  // ( no * ) 

And change the helper to

// helper function
setupGetRecords( MockPostgresDb* db     ,
                 MockCursor     cursor ) 
{
    EXPECT_CALL( *db, getRecords(_,_) )
        .Times( 1 )
        .WillRepeatedly(::testing::Return( cursor ) ) ;
}

and getting some mismatched types of compilation errors. What went wrong? Thanks.

Upvotes: 3

Views: 8585

Answers (1)

Mike van Dyke
Mike van Dyke

Reputation: 2878

The main problem here is that in the function void original_get_method( const int id_1, const int id_2 , PostgresDb db) the PostgresDb is passed by value, i.e. the copy constructor of PostgresDb will be called. This means that inside of the original_get_method function you don't have a MockPostgresDb-Object but a simple PostgresDb and that's why not the mocked method gets called but simply the original implementation. Furthermore the getRecords function is not virtual, i.e. the mocked method in class MockPostgresDb just shadows the function of PostgresDb (and so there's no way to tell the program at run-time which function to call, i.e. if there is a PostgresDb-Object or reference to such an object it will always call the function in that class).

So first things to change:

class PostgresDb
{
public :
    // typedef the CursorPtr, this is just a smart pointer.
    // sth like 
    typedef shared_ptr<DbDataType> CursorPtr ;

    PostgresDb( const std::string & connString ) ;

    // ===> make this method virtual <====
    virtual CursorPtr getRecords( const int id_1 ,
                          const int id_2 ) ;
}

// pass PostgresDb by reference
void original_get_method( const int id_1, const int id_2 , PostgresDb& db);

These two changes will call the mocked method in original_get_method.


Next problem is as pointed out in the comments:

MOCK_METHOD2( getRecords, CursorPtr*( const int , const int  ) ) ;

The mock method has a different signature then the base class -> function will not get overwritten in derived (mocked) class (i.e. they are two completely different functions). This is what you want:

MOCK_METHOD2( getRecords, CursorPtr( const int , const int  ) ) ;

Next problem is the following:

typedef shared_ptr<DbDataType> CursorPtr ;

You define your new type CursorPtr and then inherit from it

class MockCursor : public CursorPtr {}

But MockCursor does not inherit from DbDataType but from std::shared_ptr, i.e. they are nothing alike. Instead let MockDbDataType inherit from DbDataType and create a new type MockCursor:

typedef std::shared_ptr<MockDbDataType> MockCursor;

And then this should compile fine:

setupGetRecords( MockPostgresDb* db     ,
                 MockCursor     cursor ) 
{
    EXPECT_CALL( *db, getRecords(_,_) )
        .Times( 1 )
        .WillRepeatedly(::testing::Return( cursor ) ) ;
}

I haven't tested this code, so if there are any problems let me know.

Upvotes: 4

Related Questions