【发布时间】:2012-09-30 01:23:04
【问题描述】:
我正在尝试做 tdd 并使用 mongodb 作为数据库。但我无法解决模拟 mongodb 的问题。是否有能力模拟 mongodb 以在 .NET 中进行单元测试?
更新
我发现非常好的解决方案阅读博客。 你可以找到它here:
【问题讨论】:
标签: c# .net unit-testing mongodb mocking
我正在尝试做 tdd 并使用 mongodb 作为数据库。但我无法解决模拟 mongodb 的问题。是否有能力模拟 mongodb 以在 .NET 中进行单元测试?
更新
我发现非常好的解决方案阅读博客。 你可以找到它here:
【问题讨论】:
标签: c# .net unit-testing mongodb mocking
您应该在在 MongoDB 之上模拟一个层,而不是模拟 MongoDB。
您可能需要考虑一个接口,该接口公开您的存储库上的操作,这些操作与底层数据存储无关。例如,您可能需要一个抽象出Student 类型操作的接口,如下所示:
public interface IStudentOperations
{
void Add(Student student);
}
当您创建其他依赖项时,您会注入上述接口的实例,或者您选择的任何更高级别的抽象。
重点是,不要直接暴露MongoDB。
一旦你这样做了,你就可以模拟你创建的所有你想要的接口,有一个实现来测试模拟实现,然后一个实际的实现带有它自己的测试来验证实现上的操作是正确的,当底层使用 MongoDB 实现。
虽然肯定是possible to mock most of MongoDB's classes (as the methods are virtual),但您获得了与持久性无关的好处;如果你想切换到 CouchDB 或 elasticsearch,你不必改变对这些接口的调用,你只需创建一个新的实现。
因为you are trying to test the implementation of the repository,那你一般没问题,前面已经说了,MongoDB的大部分函数都是virtual,对大部分mocking库都很友好。
也就是说,您必须确保将MongoDatabase 传递到您的存储库(而不是在存储库中创建它),以便在您的单元中测试,您可以创建适当的模拟,然后将其传递到您的存储库实现进行测试。
【讨论】:
您需要一个存储库/DAL 层来隐藏实现细节。像这样的:
public interface IDataContext<T>
{
// Query
IList<T> GetAll<T>();
IList<T> GetByCriteria<T>(Query query);
T GetByID<T>(string id);
// CUD
void Add(T item);
void Delete(T item);
void Save(T item);
}
模拟添加/删除/保存看起来很简单,有趣的部分是查询功能。幸运的是,由于 mongo C# 驱动程序支持 LINQ 表达式,我们可以使用 LINQ 作为查询语言,而不是重新发明轮子。
例如,生产代码可能如下所示:
// collection is a MongoCollection<T> object
var items = collection.AsQueryable().Where(...linq expression...);
还有单元测试代码(如果你使用 Shim,MS 测试):
using (ShimsContext.Create())
{
ShimLinqExtensionMethods.AsQueryableOf1MongoCollectionOfM0(
(MongoCollection<T> x) => Fake_DB_Collection.AsQueryable());
// After this, the above "collection.AsQueryable()" will be mocked as
// an in-memory collection, which can be any subclass of IEnumerable<T>
}
【讨论】:
看到这个类似的问题:Mocking database in node.js?
简而言之,模拟 MongoDB 不是正确的方法。模拟您的存储库足以测试您自己的单元,但如果您想确保正确使用它,或者如果您依赖唯一性约束等,您仍然需要针对 MongoDB 进行测试。
【讨论】: