Moq模拟IMongoCollection时Database为空的单元测试问题求助
问题:单元测试中访问
IMongoCollection.Database返回null 在单元测试调用SaveEmployee方法时,发现collection.Database返回null,无法继续执行后续的Client.StartSessionAsync操作。相关测试代码如下:
[Fact] public async void SaveEmployee_Should_Upsert_The_Employee() { var mockDbService = new Mock<IDatabaseService>(); var employeeMockCollection = new Mock<IMongoCollection<Employee>>(); mockDbService .Setup(service => service.GetCollection("Employee")) .Returns(employeeMockCollection.Object); // 原代码中collectionMock应为employeeMockCollection,此处修正笔误 employeeMockCollection .Setup( collection => collection.UpdateOneAsync( It.IsAny<FilterDefinition<Employee>>(), It.IsAny<UpdateDefinition<Employee>>(), It.IsAny<UpdateOptions>(), CancellationToken.None ) ) .Returns(Task.FromResult(new UpdateResult.Acknowledged(1, 1, null))); await SaveEmployee(employeeMockCollection.Object); } public async Task SaveEmployee(IMongoCollection<Employee> collection) { var session = await collection .Database .Client .StartSessionAsync(new ClientSessionOptions()); // collection.Database 此处为null }
解决方案
Moq创建的Mock对象,所有未手动配置的属性默认返回null。你需要逐层Mock依赖链,依次配置IMongoCollection的Database属性、IMongoDatabase的Client属性,才能让链式调用不返回null。
修改后的测试代码如下:
[Fact] public async void SaveEmployee_Should_Upsert_The_Employee() { // 1. Mock IMongoClient,并配置StartSessionAsync返回Mock会话 var mockClient = new Mock<IMongoClient>(); mockClient.Setup(c => c.StartSessionAsync(It.IsAny<ClientSessionOptions>(), It.IsAny<CancellationToken>())) .ReturnsAsync(Mock.Of<IClientSessionHandle>()); // 2. Mock IMongoDatabase,配置其Client属性返回上面的MockClient var mockDatabase = new Mock<IMongoDatabase>(); mockDatabase.Setup(db => db.Client).Returns(mockClient.Object); // 3. Mock IMongoCollection<Employee>,配置其Database属性返回上面的MockDatabase var employeeMockCollection = new Mock<IMongoCollection<Employee>>(); employeeMockCollection.Setup(col => col.Database).Returns(mockDatabase.Object); // 保留原有的UpdateOneAsync配置 employeeMockCollection .Setup( collection => collection.UpdateOneAsync( It.IsAny<FilterDefinition<Employee>>(), It.IsAny<UpdateDefinition<Employee>>(), It.IsAny<UpdateOptions>(), CancellationToken.None ) ) .Returns(Task.FromResult(new UpdateResult.Acknowledged(1, 1, null))); var mockDbService = new Mock<IDatabaseService>(); mockDbService .Setup(service => service.GetCollection("Employee")) .Returns(employeeMockCollection.Object); await SaveEmployee(employeeMockCollection.Object); }
关键说明
- 必须逐层Mock依赖链:
IMongoCollection→IMongoDatabase→IMongoClient,每个层级的属性都要手动配置返回对应的Mock对象。 - 原代码中
SaveEmployee方法是同步方法,但内部调用了异步的StartSessionAsync,需改为async Task方法并添加await,避免异步操作未等待的潜在问题。
内容的提问来源于stack exchange,提问作者Venkat
相关产品推荐
相关产品推荐

