Search code examples
c++googletestgooglemock

Gmock const method not called instead calling the original method


I have interface which is defined as in .h file

namespace diagnostic{
class class1interface{
virtual int readpowerstate()const =0;
virtual int readparameters() = 0;
}
class class1 : public class1interface{
int readpowerstate()const;
int readparameters();}};

in .cc file i have the function

int diagnostic::readparameters(){
if(diagnostic::readpowerstate ==1)
    { //Dothis}
else
    {return 0}}

i have to execute the else part since by default the if will get called when i run the program. So i tried to use gmock as follows.

class Mock_class : public diagnostic::class1interface{
public:
Mock_class(){}
MOCK_METHOD0(readparameters,int());
MOCK_CONST_METHOD0(readpowerstate,int());};

and the gmock test i wrote as follows // Test the failure of Read Parameters

TEST_F(TestBase, readParam_failure){
Mock_class mock_class;
class1 *class_dummmy = new class1();
EXPECT_CALL(mock_class, readpowerstate()).WillOnce(Return(0));
class_dummy->readparameters;
EXPECT_EQ(0, class_dummy->readparameters());}

when i'm executing this program i'm getting the error that error: Actual function call count doesn't match EXPECT_CALL(mock_class, readpowerstate())... Expected: to be called at least once Actual: never called - unsatisfied and active

what is the solution for this since i'm new to gmock.


Solution

  • Module tests are all about testing an isolated module (like an instance of a selected class) in a mocked environment, specifically, how that module communicates with other objects, and how it responds to various results of these calls. To make this possible, one uses mocks in place of that other real objects. Mock classes allow to both:

    • configure expectations regarding, e.g., the amount/sequence of calls and/or the values of arguments of these calls to specific functions, and verify those by registering all interactions;
    • program the results of these expected calls that are returned as if a real object performed some action and responded to the object under test.

    This makes it possible to test an object as if it were surrounded by real components, without actually having those. E.g., a device manager can be tested on how it responds to device failures, by mocking a class representing a device and programming that mock to return an error code when some status function is invoked by the manager. That is, no real device class is used, and also, no real (faulty!) device itself is needed to be connected and configured. The mock will pretend to be that device, and what's important, this will all be on a software level.

    This, however, is possible only if the class itself is designed in a way that allows us to somehow inject mocked objects in place of their real counterparts. Most importantly, the objects in the system need to communicate via interfaces and virtual calls. That is, the aforementioned device manager should not be communicating with, e.g., DeviceA (a concrete class name), but instead, some DeviceInterface, and so both DeviceA and a newly created mock DeviceMock could implement that interface and be used in that manager. This way the manager will not even know that it is beeing tested and communicates with a mocked object, and not the real device wrapper.

    That is, currently, although you create a mock for class1interface you don't actually use that mock. Instead, you try to test class1. Creating a mock for class1interface is useful only if you aim to test some other component (like a class) that communicates with class1 through class1interface, not class1 itself.

    So, having a mock for class1, you can e.g. test class2. But this requires this class design to meet the conditions I mentioned previously: communicating via interfaces and ability to inject a mock class.

    So to meet the conditions, you'd have to rewrite the code:

    int class2::readdata()
    {
        std::unique_ptr<diagnostic::class1interface> classint
             = std::make_unique<diagnostic::class1>();
        int value = classint->readparameters();
        return value;
    }
    

    to (it's just an example of questionable usefulness, you'd have to adjust it to your needs):

    int class2::readdata(diagnostic::classinterface* classint)
    {
        int value = classint->readparameters();
        return value;
    }
    

    And so you could write a test for class2, injecting a mock of class1:

    TEST_F( TestClass2, readParam_failure )
    {
        // Mocks configuration
        Mock_class mock_class;
        EXPECT_CALL( mock_class, readparameters() ).WillOnce(Return(0));
    
        // System under test configuration
        diagnostic::class2 sut;
    
        // Test itself
        EXPECT_EQ( 0, sut.readdata(&mock_class) );
    }
    

    This way you check that the call to class2::readdata is properly fowarded to class1interface::readparameters, and its result is returned.