如何对 MongoDB 查询过滤器进行单元测试?

时间:2021-02-02 15:22:23

标签: c# .net mongodb unit-testing mongodb-query

我有一个类似于以下的场景(为了清楚起见进行了简化):

public class ExampleRepository
{
    private readonly IMongoDatabase _db;

    public ExampleRepository(IMongoClient mongoClient)
    {
        this._db = mongoClient.GetDatabase("database");
    }

    public async Task<IEnumerable<Item>> GetItemsUsingFilter(Guid ownerId, DateTimeOffset createdSince, IEnumerable<ItemType> typesToIgnore)
    {
        var cursor = await this._db.GetCollection<Item>("Items")
            .FindAsync(item =>
                item.OwnerId == ownerId
                &&
                item.CreatedDate >= createdSince
                &&
                !typesToIgnore.Contains(item.Type)
            .SortByDescending(item => item.UserRating)
            .Limit(10);

        return await cursor.ToListAsync();
    }
}

我想编写单元测试来验证我的查询过滤器(以及排序和限制调用)的正确性,但我不知道如何设置测试数据来这样做。

我尝试模拟 IMongoDatabase 并设置 GetCollection 调用以返回模拟 IMongoCollection,但这不是正确的方法,因为我需要对真正的 MongoCollection 调用 FindAsync 调用。

我考虑通过拆分 GetCollection 调用然后使用标准 LINQ 应用过滤来更改存储库,但我不想必须从数据库返回我的整个集合,然后在存储库层中查询它。

>

我发现了几个人对 MongoDB 进行单元测试的例子,但这些都涉及模拟 FindAsync 调用,这不是我需要做的。

我还考虑在单独的类中将我的过滤器声明为 Expression>,因此我可以单独测试它,但我想在沿着这条路线走之前探索其他选项,因为它增加了存储库层的复杂性。

1 个答案:

答案 0 :(得分:0)

我没有使用过 MongoDB,但这是我从纯单元测试的角度来看的方法:

  • 观察测试中的方法有四个输入:IMongoClient 依赖项(我认为是间接输入)和三个参数(直接输入)。
  • 创建一个实现 IMongoDatabase (MD) 的对象并模拟 IMongoClient 以返回它。
  • 创建一个实现 IMongoCollection (MC) 的对象,并由 MD 的 GetCollection 方法返回; MC 实际上是你的测试数据。
  • 定义三个参数以传递给被测方法。

现在您可以执行测试了。

请注意,MC 的实现包括 FindAsync 等方法,但这没关系,因为您的目的不是测试 MongoDB 的功能,而是测试方法的流程和行为。

看看这个过于简化的例子(基于你的代码):

    public async Task<IEnumerable<string>> GetItemsUsingFilter()
    {
        var cursor = await this._db.GetCollection<string>("Items")
            .SortByDescending()
            .Limit(10);

        return await cursor.ToListAsync();
    }

如果 GetCollection 在生产环境中返回 12 个项目,“A”..“L”,我们希望返回“L”..“C”。此外,我们希望我们的测试失败,例如,如果其他开发人员错误地在 SortByDescending 之前移动了 Limit(这将导致生产代码返回“J”..“A”)。