在Hippo mock中,一个mock是否可以用于具有不同返回值的多个预期调用?

Can a mock be reused for multiple expected calls with different return values in Hippo Mocks?

本文关键字:mock 返回值 调用 一个 Hippo 是否 用于      更新时间:2023-10-16

我正在使用Hippo Mocks取得巨大成功,但是我有一种情况,我不能完全弄清楚如何正确设置。测试中的代码看起来像这样:

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

其中IRecord::at()返回一个具有纯虚getValue()方法的IColumn&。我正试图用IrecordIColumn的模拟版本测试我的代码:

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")));

但是我想在lastName的下一个期望中重用IColumn模拟。

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

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

根据本教程,我尝试限制"firstName"answers"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")));

但我仍然得到"John"两个getValue()呼叫。

Q:是否有可能重用IColumn接口并告诉Hippo Mocks在每个getValue()调用中返回不同的值,或者我是否为每个参数创建单独的IColumn mock ?注意:我的实际实现将有两个以上的参数,因此重用IColumn模拟可以减少每个单元测试的大量设置。

我不确定您的问题是什么,但是当我运行以下代码时,使用git存储库

的版本
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"));