如何存根/模拟const函数

时间:2014-05-26 08:02:13

标签: c++ unit-testing mocking stub

我想计算A类中某个函数的调用次数,这是由B类中的另一个函数调用的。这是在B类的类测试中完成的,在这个测试中,A类是存根的。

在这里,我尝试用C ++代码解释所涉及的类:

class X
{
  const void Method() const = 0;
}

class A : public X
{
  const void Method() const;
}

class AStub : public A
{
  const void Method() const;
  U32 getNumberOfCallsToMethod();
}

class B
{
  void runAlgorithm();
  A* getA(); // returns pointer to the A instance used by B
}

class BTest
{
  void test_runAlgorithm()
  {
    B b;
    // b is setup to use a stub of A rather than A..
    // ...
    U32 before = ((AStub*)b.getA())->getNumberOfCallsToMethod();
    b.runAlgorithm();
    U32 after = ((AStub*)b.getA())->getNumberOfCallsToMethod();

    // Verify that Method() has been run exactly once
    ASSERT_EQUAL("Unexpected number of calls to Method()",
                 before + 1, after);
  }
}

现在我的问题。如何使用" dummy"覆盖我的存根中的Method()。计算通话次数的变量?我有虚拟到位,它按预期调用,但我不能使它增加一个计数器,因为它被声明为const。我想在我的AStub中添加一个计数器,并让AStub :: Method()增加计数器作为虚拟实现的一部分,但考虑到它的声明方式,这看起来很棘手。

我不能使用像谷歌模拟或类似的任何模拟框架,但必须有一些共同的解决方案来解决这个问题。人们通常会如何处理这个小障碍?

由于

3 个答案:

答案 0 :(得分:2)

如果您正在使用继承,则可能需要将Method声明为虚拟:

class X
{
  virtual void Method() const = 0;
};

(同样删除const void,因为它没有意义 - const在成员函数足以使其成为const函数之后)

然后使用mutable关键字告诉编译器“即使在const调用中,我希望此特定成员变量能够更改” - 调用此变量numCalls,添加默认构造函数为零numCalls

class AStub : public A
{
public:
  AStub() : numCalls(0) {}
  void Method() const;
  U32 getNumberOfCallsToMethod();
private:
  mutable U32 numCalls;
}

最后,执行Method,增加调用次数,然后调用原始函数:

void AStub::Method() const
{
   numCalls++;
   A::Method(); 
}

答案 1 :(得分:2)

如果问题是如何在const方法中修改成员变量,那么答案很简单:使用mutable关键字。

这样的事情应该有效:

class AStub : public A
{
  public:
    const void Method() const{ ++n; }


  mutable int n;
};

答案 2 :(得分:1)

您可以使用模拟框架为您完成工作。无需实现自己的模拟类(AStub)。 以下是Fake-It的使用方法。一个简单的C ++模拟框架:

class X
{
public:
    virtual const void foo() const = 0;
};
class A : public X
{
public:
    virtual const void foo() const override {}
};
class B
{
    A& _a;
public:
    B(A& a):_a(a){}

    void runAlgorithm() { _a.foo(); }
    A& getA() { return _a; }
};

A a;
Mock<A> mock(a);
Spy(Method(mock,foo)); // Spy A::foo on the mock object.

// Instantiate B (class under test) and inject the mock instance.
B b(mock.get());

// Run the tested method.
b.runAlgorithm();

// Verify the A::foo of the injected object was invoked exactly once.
Verify(Method(mock,foo)).Exactly(Once);