1

我使用 Hippo Mocks 取得了巨大的成功,但我有一种情况,我不太清楚如何正确设置。被测代码看起来像这样:

auto firstName = record.at("firstName").getValue();
auto lastName = record.at("lastName").getValue();

WhereIRecord::at()返回 a IColumn&,它有一个纯虚getValue()方法。我正在尝试使用和的模拟版本测试我的Irecord代码IColumn

auto mockRec = mocks.InterfaceMock<IRecord>();
auto mockCol = mocks.InterfaceMock<IColumn>();

我可以很好地设定期望firstName

mocks.OnCall(mockRec, IRecord::at).With("firstName").Return(std::ref(*mockCol));
mocks.OnCall(mockCol, IColumn::getValue).Return(std::string("John")));

但我想将IColumn模拟重用于下一个期望lastName

mocks.OnCall(mockRec, IRecord::at).With("lastName").Return(std::ref(*mockCol));
mocks.OnCall(mockCol, IColumn::getValue).Return(std::string("Doe")));

getValue()但是当我运行它时,Hippo Mocks 会为这两个调用返回“John” 。

按照教程,我尝试限制“firstName”和“lastName”调用的顺序:

auto& firstCall = mocks.OnCall(mockRec, IRecord::at).With("firstName").Return(std::ref(*mockCol));
mocks.OnCall(mockCol, IColumn::getValue).After(firstCall).Return(std::string("John")));

auto& lastCall = mocks.OnCall(mockRec, IRecord::at).With("lastName").Return(std::ref(*mockCol));
mocks.OnCall(mockCol, IColumn::getValue).After(lastCall).Return(std::string("Doe")));

getValue()但是两个电话我仍然得到“约翰” 。

问:是否可以重用IColumn接口并告诉 Hippo Mocks 在每次调用时返回不同的值,getValue()就像我需要的那样,或者我是否坚持IColumn为每个参数创建单独的模拟?注意:我的实际实现将有两个以上的参数,因此重用IColumn模拟减少了每个单元测试的大量设置。

4

1 回答 1

2

我不确定您的情况是什么问题,但是当我使用git repository 的版本运行以下代码时

struct IColumn {
    virtual std::string getValue() = 0;
}; 

struct IRecord {
    virtual IColumn& at( std::string ) = 0;
};

void main()
{
    MockRepository mocks;

    auto mockRec = mocks.Mock<IRecord>();
    auto mockCol = mocks.Mock<IColumn>();

    auto& firstCall = mocks.OnCall(mockRec, IRecord::at).With("firstName").Return(std::ref(*mockCol));
    mocks.OnCall(mockCol, IColumn::getValue).After(firstCall).Return(std::string("John"));

    auto& lastCall = mocks.OnCall(mockRec, IRecord::at).With("lastName").Return(std::ref(*mockCol));
    mocks.OnCall(mockCol, IColumn::getValue).After(lastCall).Return(std::string("Doe"));

    std::cout << mockRec->at("firstName").getValue() << " " 
              << mockRec->at("lastName").getValue() << "\n";
}

我得到正确的输出。

John Doe

我发现我几乎总是使用

mocks.autoExpect = false;

但在这种情况下,它没有任何区别。

编辑:

如果您需要更大的灵活性,可以执行以下操作:

std::vector<IColumn*> cols;

cols.push_back( mocks.Mock<IColumn>() );
cols.push_back( mocks.Mock<IColumn>() );

mocks.OnCall(mockRec, IRecord::at).With("firstName")
     .Return(std::ref(*cols[0]));
mocks.OnCall(mockRec, IRecord::at).With("lastName")
     .Return(std::ref(*cols[1]));

mocks.OnCall(cols[0], IColumn::getValue)
     .Return(std::string("John"));
mocks.OnCall(cols[1], IColumn::getValue)
     .Return(std::string("Doe"));

这将按任何调用顺序工作。或者,您也可以使用Do

std::map<std::string, IColumn*> map;

map["firstName"] = mocks.Mock<IColumn>();
map["lastName"] = mocks.Mock<IColumn>();

mocks.OnCall(mockRec, IRecord::at)
     .Do( [&map]( std::string& key){ return std::ref(*map[key]); } );

mocks.OnCall(map["firstName"], IColumn::getValue)
     .Return(std::string("John"));
mocks.OnCall(map["lastName"], IColumn::getValue)
     .Return(std::string("Doe"));
于 2013-03-09T17:47:26.380 回答