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
相关产品推荐
相关产品推荐

