Search code examples
c++unit-testingmisra

Unit test a call to function of instance variable


I have some C++ code similar to the example given below. I would like to write a unit test to verify that mFlashLamp.trigger is called exactly five times. However, up to now I was not able to figure out a good way to do this.

I have the following restraints: Compliance to Misra / GoogleTest / GoogleMock

include <iostream>

class FlashLamp
{
public:
    virtual void trigger(){
        std::cout << "Trigger FlashLamp" << std::endl;
    }
};

class Spectrometer
{
public:
    FlashLamp mFlashLamp;

    void foo(){
        for( int i=0; i<5; i++ ){
            mFlashLamp.trigger();
        }
    }

};

int main(){
    Spectrometer S;
    S.foo();
    return 0;
}

Does anybody have a good and clean solution for a unit test. One solution I can think of is to

class Spectrometer
{
public:
    FlashLamp mFlashLamp;
    FlashLamp* pFlashLamp;
}

have an additional pointer to the instance variable and use this to access the trigger. But this would mean some code bloat as it requires a null pointer check on every dereference. Does anybody have an idea for a better solution.

PS: I really tried to come up with a good title but couldn't. If someone has any improvements please feel free to edit it.


Solution

  • The idiomatic way in unit testing is to use interfaces and Mock Classes:

    #include <iostream>
    
    // The interface definition
    struct IFlashLamp {
        virtual ~IFlashLamp() {}
        virtual void trigger() = 0;
    };
    
    class FlashLamp : public IFlashLamp 
    {
    public:
        virtual void trigger() override {
            std::cout << "Trigger FlashLamp" << std::endl;
        }
    };
    
    class Spectrometer
    {
    public:
        IFlashLamp& mFlashLamp;
    
        Spectrometer(IFlashlamp& flashLamp) : mFlashLamp(flashLamp) {}
        void foo(){
            for( int i=0; i<5; i++ ){
                mFlashLamp.trigger();
            }
        }
    
    };
    

    You'll implement the interface with a mock class, that allows you to inspect the expectations regarding calls to the interface:

    class FlashLampMock : public IFlashlamp {
        int triggerCallCounter;
    public:
        FlashLampMock() : triggerCallCounter(0) {}
        virtual void trigger() override {
            ++triggerCallCounter;
        }
        int getTriggerCallCounter() const { return triggerCallCounter; }
    };
    

    This is the unit test then:

    int main(){
        FlashLampMock flashLampMock;
        Spectrometer S(FlashLampMock);
        S.foo();
        assert(flashLampMock.getTriggerCallCounter() == 5);
        return 0;
    }