You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NUnit使用InMemoryDatabase测试时查询返回计数为0问题求助

问题根源
  • 测试用例天然隔离:NUnit 中每个标记[Test]的方法都是独立运行的测试用例,不会继承前一个测试的执行结果。同时[SetUp]标记的方法会在每个测试方法执行前都运行一次,每次都会重新初始化ApplicationDbContext、服务实例,相当于第一个测试写入的数据在第二个测试启动时就被完全重置了。
  • 内存数据库默认隔离:你当前的UseInMemoryDatabase("TestDb")配置没有绑定全局服务提供器,每次新建DbContextOptions都会生成独立的内存数据库实例,就算数据库名称相同,不同上下文也无法共享数据。
  • 潜在的持久化缺失:如果CreatePaymentCalendar方法内部没有调用IUnitOfWork的SaveChanges/Commit方法,写入的数据只会停留在上下文追踪缓存中,不会真正持久化到内存数据库。
修复方案

方案1:合并写入查询逻辑(最符合单元测试隔离原则)

单元测试要求每个用例可以独立运行,建议把数据初始化和校验逻辑放到同一个测试方法中,同时将异步调用改为await避免死锁:

[Test]
public async Task GetPaymentCalendar_AfterCreate_ReturnCorrectCount()
{
    // 1. 初始化写入数据
    var factoryId = "25aa09a6-006c-4571-ae45-68b697a54fec";
    var request = new List<PaymentCalendarCreateRequest>();
    for (int i = 0; i < 25 * 12; i++)
    {
        request.Add(
            new PaymentCalendarCreateRequest
            {
                Month = DateTime.Now.AddMonths(i).Month,
                Year = DateTime.Now.AddMonths(i).Year,
                IsClosed = false,
                FactoryId = factoryId
            }
        );
    }
    var createResult = await _paymentCalendarService.CreatePaymentCalendar(request);
    Assert.IsTrue(createResult.Succeeded);

    // 2. 查询校验数量
    var response = await _paymentCalendarService.GetPaymentCalendar(factoryId);
    Assert.AreEqual(25*12, response.Count);
}

你可以删除原来分开的两个测试方法,改用这个合并后的用例即可。

方案2:共享全局初始化(适合多测试用例共享同一份基础数据)

如果需要多个测试用例共享同一份测试数据,可以用[OneTimeSetUp]代替[SetUp],整个测试类只会初始化一次服务和内存数据库:

[OneTimeSetUp]
public async Task OneTimeInit()
{
    var options = new DbContextOptionsBuilder<ApplicationDbContext>()
        // 加这个配置确保跨上下文共享同名内存数据库
        .UseInMemoryDatabase("TestDb")
        .UseApplicationServiceProvider(new ServiceCollection()
            .AddEntityFrameworkInMemoryDatabase()
            .BuildServiceProvider())
        .Options;
    var currentUserServiceMock = new Mock<ICurrentUserService>(MockBehavior.Strict);
    currentUserServiceMock.Setup(_ => _.UserId).Returns(Guid.NewGuid().ToString);
    var dateTimeServiceMock = new Mock<IDateTimeService>(MockBehavior.Strict);
    dateTimeServiceMock.Setup(_ => _.Now).Returns(DateTime.Now);
    _context = new ApplicationDbContext(options, currentUserServiceMock.Object, dateTimeServiceMock.Object);
    _unitOfWork = new UnitOfWork(_context, dateTimeServiceMock.Object, currentUserServiceMock.Object);
    _paymentCalendarService = new PaymentCalendarService(_unitOfWork);

    // 初始化完成后统一写入测试数据
    var request = new List<PaymentCalendarCreateRequest>();
    for (int i = 0; i < 25 * 12; i++)
    {
        request.Add(
            new PaymentCalendarCreateRequest
            {
                Month = DateTime.Now.AddMonths(i).Month,
                Year = DateTime.Now.AddMonths(i).Year,
                IsClosed = false,
                FactoryId = "25aa09a6-006c-4571-ae45-68b697a54fec"
            }
        );
    }
    await _paymentCalendarService.CreatePaymentCalendar(request);
}

调整后原来的两个独立测试用例就可以正常运行了。

内容的提问来源于stack exchange,提问作者Danijel Boksan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 15:18:03