如何访问Google模拟中的私人成员

时间:2015-05-22 03:12:32

标签: c++ unit-testing mocking googlemock

我正在尝试为具有私有向量的类编写模拟,该向量将数据插入到私有向量中。但是,我没有看到使用Google Mock的方法。理想情况下,我想在我的界面中没有与测试相关的任何内容。此外,我不想使私有向量受保护并对类进行子类化并添加一个访问器方法,因为这会导致我的代码泄漏其实现。

这是我到目前为止所拥有的。我想要完成的是使用Fake类插入数据,并使用Mock类在指向Fake类的指针上调用Real :: first()以便我可以使用Fake' s矢量而不是真实的。编译此程序时,返回-1而不是4。

#include <iostream>
#include <vector>
#include <gmock/gmock.h>

using namespace std;
//using ::testing::_;
using ::testing::Invoke;

class A {
protected:
    vector<int> a;

public:
    virtual int first() = 0;
    virtual ~A() {}
};

class Real : public A {
public:
    virtual int first() {
        cout << "size: " << a.size() << endl;
        return a[0];
    }
};

class Fake : public A {
public:
    virtual void insert(int b) {
        a.push_back(b);
        cout << a.size() << endl;
    }

private:
    virtual int first() { return -1; }
};

class Mock : public A {
public:
    Mock(Fake* c) :
        c_(c) {}

    MOCK_METHOD0(first, int());

    void delegate() {
        ON_CALL(*this, first())
            .WillByDefault(Invoke((Real*)c_, &Real::first));
    }

private:
    Fake* c_;
};

int main(void) {
    Fake c;
    c.insert(4);

    Mock z(&c);

    z.delegate();

    cout << z.first() << endl;
    return 0;
}

有谁知道我做错了什么?或者有更简单的方法来实现这一目标吗?

2 个答案:

答案 0 :(得分:1)

赋予c的实现实例Mock是一个Fake对象,并且指向它的指针的数量不会变为Real。由于FakeReal都从first()派生A,即使编译器认为Fake对象first()已成功调用它调用first()的{​​{1}}函数。

说出你想要的东西并不是那么容易,因为你的例子是如此之小(在最小的情况下,嘲弄并不是真的必要),但是有很多方法可以实现你理想的行为,有些偏离我的头脑:

选项1

Real中提供first的默认定义,并从A中删除定义:

Fake

选项2

class A { protected: vector<int> a; public: virtual int first() { return a[0]; } virtual ~A() {} }; class Fake : public A { public: virtual void insert(int b) { a.push_back(b); cout << a.size() << endl; } }; first的工作定义。我知道,我知道,这段代码并不属于Fake,但它可以快速修复这种琐碎的案例。

Fake

选项3

如果所有这一切都不是在class Fake : public A { public: virtual void insert(int b) { a.push_back(b); cout << a.size() << endl; } private: virtual int first() { return a[0]; } }; A中调用打印输出,我建议你嘲笑出去。

答案 1 :(得分:0)

这有点突破了第一个要求,但为使测试工作而添加的样板数量很少。

将存储与A和模拟分离到它自己的类中,并将其注入构造函数中。

class AStorage {
vector<int> vals;
};

class A {
AStorage& storage;

public:
A(AStorage& stor) :
storage(stor) {}
};

不幸的是,A不能拥有自己的存储空间。但是,测试现在更容易,因为测试将引用存储对象,允许它在幕后数据后面进行更改。