How to use gmock to test that a class calls it's base class' methods
Asked Answered
D

1

7
class Foo {
public:
    int x;
    int y;

    void move(void);
};

class SuperFoo: public Foo {
public:
    int age;

    void update();
};

SuperFoo::update(void) {
    move();
    age++;
}

I'm just starting out with C++ and unit testing, I have some code resembling the above and I want to use gmock to test that SuperFoo::update() calls the base class' move() method. What would be that best way to attack this type of situation?

Dioptase answered 25/8, 2014 at 13:43 Comment(2)
I don't know about gmock, but why would you test that? You test the input / ouput of a method, not how it works internaly! If you find a better way to do something in a specific subclass case, then you don't need to call super... Otherwise, just add a non virtual method on base class which is used by your program, and this class calls a virtual method (or something similar using CRTP) defined in your derived class.Suzette
I'm not after testing the behaviour of the move() method, I've already got unit tests for that in Foo's test suite, doing it all again for SuperFoo seems like needless duplication of effort. In terms of SuperFoo all I care about is that the move() method is actually used in the correct place.Dioptase
C
5

One way is to make the move method virtual, and create a mock of your class:

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

class Foo {
public:
    int x;
    int y;

    virtual void move(void);
    //^^^^ following works for virtual methods
};
// ...

class TestableSuperFoo : public SuperFoo
{
public:
  TestableSuperFoo();

  MOCK_METHOD0(move, void ());

  void doMove()
  {
    SuperFoo::move();
  }
};

Then in your test, setup the corresponding call expectations

TEST(SuperFoo, TestUpdate)
{
  TestableSuperFoo instance;

  // Setup expectations:
  // 1) number of times (Times(AtLeast(1)), or Times(1), or ...
  // 2) behavior: calling base class "move" (not just mock's) if "move" 
  //    has side-effects required by "update"
  EXPECT_CALL(instance, move()).Times(testing::AtLeast(1))
    .WillRepeatedly(testing::InvokeWithoutArgs(&instance, &TestableSuperFoo::doMove));

  const int someValue = 42;
  instance.age = someValue;
  // Act
  instance.update();
  // Assert
  EXPECT_EQ(someValue+1, instance.age);
}
Concettaconcettina answered 25/8, 2014 at 15:1 Comment(1)
Excellent, that did the trick. Thanks, will upvote once I'm allowed to!Dioptase

© 2022 - 2024 — McMap. All rights reserved.