You need to enable JavaScript to run this app. 如何在.NET Core中为MongoDB的IMongoCollection分页扩展方法编写单元测试
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET Core中为MongoDB的IMongoCollection分页扩展方法编写单元测试

单元测试实现方案

你可以根据场景选择两种测试方案:

方案1:基于Moq的纯单元测试(无需真实MongoDB实例)

依赖安装

先安装对应NuGet包:

  • xunit(测试框架,也可替换为NUnit)
  • Moq(依赖Mock框架)
  • MongoDB.Driver(MongoDB官方驱动)
  • xunit.runner.visualstudio(Visual Studio运行测试依赖)

测试代码实现

首先定义测试用的实体类:

public class TestEntity : class
{
    public ObjectId Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

然后编写测试类,模拟IMongoCollection的调用链路,验证分页逻辑正确性:

using Moq;
using Xunit;
using MongoDB.Driver;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

public class DataPagerExtensionTests
{
    private readonly Mock<IMongoCollection<TestEntity>> _mockCollection;
    private readonly List<TestEntity> _testData;

    public DataPagerExtensionTests()
    {
        _mockCollection = new Mock<IMongoCollection<TestEntity>>();
        // 构造10条测试数据
        _testData = Enumerable.Range(1, 10).Select(i => new TestEntity
        {
            Id = ObjectId.GenerateNewId(),
            Name = $"测试{i}",
            Age = 20 + i
        }).ToList();
    }

    [Fact]
    public async Task Paginate_ShouldReturnCorrectPagedData_WhenParametersValid()
    {
        // Arrange
        var page = 2;
        var pageSize = 3;
        var expectedTotalItems = 10;
        var expectedTotalPages = 4;
        var expectedItems = _testData.Skip(3).Take(3).ToList();

        // Mock CountDocuments计数方法
        var mockCountFluent = new Mock<IFindFluent<TestEntity, TestEntity>>();
        mockCountFluent.Setup(f => f.CountDocuments(CancellationToken.None))
            .Returns(expectedTotalItems);

        // Mock 查询链路的Find、Sort、Skip、Limit、ToListAsync方法
        var mockQueryFluent = new Mock<IFindFluent<TestEntity, TestEntity>>();
        mockQueryFluent.Setup(f => f.Sort(It.IsAny<SortDefinition<TestEntity>>()))
            .Returns(mockQueryFluent.Object);
        mockQueryFluent.Setup(f => f.Skip(It.IsAny<int>()))
            .Returns(mockQueryFluent.Object);
        mockQueryFluent.Setup(f => f.Limit(It.IsAny<int>()))
            .Returns(mockQueryFluent.Object);
        mockQueryFluent.Setup(f => f.ToListAsync(CancellationToken.None))
            .ReturnsAsync(expectedItems);

        // 模拟Collection的Find方法,第一次调用返回计数用Mock,第二次返回查询用Mock
        var callCount = 0;
        _mockCollection.Setup(c => c.Find(It.IsAny<FilterDefinition<TestEntity>>(), null))
            .Returns(() =>
            {
                callCount++;
                return callCount == 1 ? mockCountFluent.Object : mockQueryFluent.Object;
            });

        // Act
        var result = await _mockCollection.Object.Paginate(
            FilterDefinition<TestEntity>.Empty,
            SortDefinition<TestEntity>.Empty,
            page,
            pageSize,
            true);

        // Assert
        Assert.Equal(page, result.CurrentPage);
        Assert.Equal(pageSize, result.PageSize);
        Assert.Equal(expectedTotalItems, result.TotalItems);
        Assert.Equal(expectedTotalPages, result.TotalPages);
        Assert.Equal(expectedItems.Count, result.Items.Count);
        Assert.Equal(expectedItems.First().Name, result.Items.First().Name);
    }
}

方案2:基于内存MongoDB的集成测试(更贴近真实场景)

如果要避免Mock链路遗漏、更准确验证MongoDB驱动的实际行为,可以用Mongo2Go包启动临时内存MongoDB实例做测试:

依赖安装

额外安装NuGet包:

  • Mongo2Go

测试代码实现

using Mongo2Go;
using Xunit;
using MongoDB.Driver;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

public class DataPagerExtensionIntegrationTests : IAsyncLifetime
{
    private MongoDbRunner _runner;
    private IMongoCollection<TestEntity> _collection;
    private readonly List<TestEntity> _testData = Enumerable.Range(1, 10).Select(i => new TestEntity
    {
        Id = ObjectId.GenerateNewId(),
        Name = $"测试{i}",
        Age = 20 + i
    }).ToList();

    public async Task InitializeAsync()
    {
        // 启动内存MongoDB实例
        _runner = MongoDbRunner.Start();
        var client = new MongoClient(_runner.ConnectionString);
        var db = client.GetDatabase("TestDb");
        _collection = db.GetCollection<TestEntity>("TestEntities");
        // 预插入测试数据
        await _collection.InsertManyAsync(_testData);
    }

    public async Task DisposeAsync()
    {
        _runner.Dispose();
    }

    [Fact]
    public async Task Paginate_ShouldReturnCorrectPagedResult_WithRealMongoInstance()
    {
        // Arrange
        var page = 2;
        var pageSize = 3;
        var sort = Builders<TestEntity>.Sort.Ascending(x => x.Age);

        // Act
        var result = await _collection.Paginate(
            FilterDefinition<TestEntity>.Empty,
            sort,
            page,
            pageSize,
            true);

        // Assert
        Assert.Equal(2, result.CurrentPage);
        Assert.Equal(3, result.PageSize);
        Assert.Equal(10, result.TotalItems);
        Assert.Equal(4, result.TotalPages);
        Assert.Equal(3, result.Items.Count);
        Assert.Equal("测试4", result.Items.First().Name);
        Assert.Equal("测试6", result.Items.Last().Name);
    }

    [Fact]
    public async Task Paginate_ShouldReturnEmptyList_WhenPageExceedsTotalPages()
    {
        // Arrange
        var page = 10;
        var pageSize = 3;

        // Act
        var result = await _collection.Paginate(
            FilterDefinition<TestEntity>.Empty,
            Builders<TestEntity>.Sort.Ascending(x => x.Age),
            page,
            pageSize,
            true);

        // Assert
        Assert.Empty(result.Items);
        Assert.Equal(10, result.TotalItems);
        Assert.Equal(4, result.TotalPages);
    }
}

注意:你当前的扩展方法里传入了paginationRequired参数但没有使用,可以在测试时补充对应逻辑的校验,比如该参数为false时直接返回全量数据的场景。

内容的提问来源于stack exchange,提问作者rakesh mahur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 15:18:02