Moq 模拟存储库模式的最佳实践

Moq 模拟存储库模式的最佳实践,moq,Moq,我从IoC/Mocking开始,并希望确保我的存储库使用“最佳实践” 我正在为我的存储库设置接口。具体实现将指向SQL,而测试将使用Moq生成“假货”。我注意到我经常使用Moq的回调功能。作者在文章中说 由于Moq在这两个方面都提供了功能,可以满足您的大部分需求,因此您需要这些工具的地方并不多。事实上,如果你认为你需要使用“回调”,你可能应该仔细看看Moq是否能自动完成你想做的事情 我已经看过了,看不到任何其他方法来实现我需要的东西——即“假”存储库。有人能告诉我这里是否有我遗漏的东西吗?有没有

我从IoC/Mocking开始,并希望确保我的存储库使用“最佳实践”

我正在为我的存储库设置接口。具体实现将指向SQL,而测试将使用Moq生成“假货”。我注意到我经常使用Moq的回调功能。作者在文章中说

由于Moq在这两个方面都提供了功能,可以满足您的大部分需求,因此您需要这些工具的地方并不多。事实上,如果你认为你需要使用“回调”,你可能应该仔细看看Moq是否能自动完成你想做的事情

我已经看过了,看不到任何其他方法来实现我需要的东西——即“假”存储库。有人能告诉我这里是否有我遗漏的东西吗?有没有办法在没有回调的情况下实现这一点

公共类UnitTest1
{
[测试方法]
公共void TestMethod1()
{
//安排
var mock=ContactRepositoryFake();
//表演
mock.Object.AddContact(新联系人(){Name=“bill”});
mock.Object.AddContact(新联系人(){Name=“jane”});
//断言
Assert.IsTrue(mock.Object.AllContacts.Count()==2);
}
公共模拟联系人RepositoryFake()
{
var_allContacts=新列表();
var mock=new mock();
mock.Setup(x=>x.AddContact(It.IsAny()))
.回拨((联系c)=>
{
_所有联系人。添加(c);
});
mock.Setup(x=>x.AllContacts)。返回(\u AllContacts);
返回模拟;
}
}
公共接口IContactRepository
{
无效添加联系人(联系人联系人);
IEnumerable AllContacts{get;}
}
公共类联系人
{
公共字符串名称{get;set;}
}
提前非常感谢!任何其他建议欢迎:-)


我个人不认为你这样做有什么问题。我看到的是,您希望模拟存储库,而不是将其存根。这意味着您希望它在测试期间“记录”并返回数据。在这种情况下,
Callback
非常有用,而且是实现这一点的唯一方法


至于注释,如果您处理的是存根而不是模拟,那么
回调
将很少使用。imo这篇文章有点笼统,没有充分理解
回调的威力

您可以只设置以下内容:

mock.Setup(x => x.AllContacts).Returns(GetExpectedContactList());
并具有一个助手函数,可返回联系人列表:

private static List<Contact> GetExpectedContactList() 
{
....
}
私有静态列表GetExpectedContactList()
{
....
}

并使用不同的助手方法返回特定的数据场景。

谢谢。很高兴知道我没有错过什么:-)不用担心,很高兴我能帮助Hi Ciaran。我认为你有点没抓住重点。问题是,我需要一种方法让Mock记录添加的内容,然后返回它们。谢谢:-)哦,好的,我现在更了解你的要求了。。。。然而,我认为您并没有真正使用回调测试核心需求,所以这就是我的困惑所在。你的代码_allContacts.Add不是你真正的代码,所以你在测试什么?事实上,我觉得,你有一个测试来确认这个列表。添加works.G'day。是的,我明白你的意思。在过去的几周里,我以上述方式写了一些“测试”之后,我越来越少地使用这种模式。不过,有几个地方证明它是有用的。感谢您的帮助:-)我不得不问,模拟数据库访问以测试存储库的价值是什么?灵魂的目的是访问数据库,我的大多数存储库中90%的逻辑都是Linq查询。这些单元测试有没有发现问题?嗨。听着,三年过去了,现在我倾向于同意你。我已经不再写这些类型的嘲弄了。它们很难编写和维护。在我看来,如果你在回购协议中使用LINQ,他们可能支持IQueryable?我在上面使用的回购模式并非如此。他们只是有“AllContacts”或“RecordsByName”之类的方法。此外,我现在偶尔实现“内存中”repos,而不是像上面那样使用mock,它只是一个实现接口并用字典支持接口的类。这些都很酷,因为我最终在“真实”代码中使用它们。我承认,我从未尝试过用模拟数据库进行单元测试。我的方法是执行多个查询,并检查它们是否相互关联,是否得到了预期的结果。例如,结果被正确过滤和排序。测试设计为针对任何样本数据运行,由于样本数据不完整而失败的测试不会失败,而是返回不确定结果。许多纯粹主义者对此会有问题,因为这种单元测试可能会根据样本数据返回不同的结果,但是我发现它们有助于发现问题。如果您将测试连接到数据源,那么这不是更像是集成测试而不是单元测试吗?我写的测试越多(今年可能有数千个!)我越来越倾向于非常简洁的测试,通常在实际的测试方法中包含数据。如果您需要测试10个不同的数据场景,那么请编写10个测试。。。也许使用基类来保持“干燥”。。。。当然,集成测试有它的位置,我想。这不一定是禁忌。