使用AutoFixture+XUnit测试时预期抛出异常却未触发的问题
问题原因及修复方案
核心问题
测试失败有两个关键原因:
- Mock实例不共享:你声明的
repositoryMock参数和注入到IReviewService中的仓储实例是两个独立的Mock对象,对前者的Setup不会影响后者的行为。 - 错误使用Moq匹配器:
It.IsAny<int>()是Moq用于配置Mock时的参数匹配器,不能作为实际调用服务方法的参数传入。
修复步骤
1. 确保Mock实例被注入到服务中
在测试方法的repositoryMock参数上添加[Frozen]特性,让AutoFixture复用这个Mock实例来构建IReviewService,这样服务内部的_repository就是你配置的这个Mock。
2. 使用具体的ID参数调用服务
让AutoFixture自动生成一个int类型的测试ID(作为测试方法参数),用这个具体值调用服务方法,而不是用It.IsAny<int>()。
修复后的测试代码
[Theory] [AutoMoqData] public async Task GetByIdAsync_WhenInvalidId_ShouldThrowNotFoundException( [Frozen] Mock<IReviewRepository> repositoryMock, IReviewService service, int invalidId) { // Arrange repositoryMock.Setup(r => r.GetByIdAsync(invalidId)) .ReturnsAsync(value: null); // Act var act = () => service.GetByIdAsync(invalidId); // Assert await act.Should().ThrowAsync<NotFoundException>() .WithMessage(ErrorMessages.REVIEW_NOT_FOUND); }
可选优化:匹配任意ID
如果你想验证服务对任意无效ID都抛出异常,可以保持Setup用It.IsAny<int>(),但调用时还是要用具体的ID:
// Arrange repositoryMock.Setup(r => r.GetByIdAsync(It.IsAny<int>())) .ReturnsAsync(value: null); // Act var act = () => service.GetByIdAsync(invalidId);
补充说明
你的AutoMoqDataAttribute配置是正常的,ConfigureMembers = true只会让AutoFixture自动配置Mock的属性返回值,不会影响方法的手动Setup。
内容的提问来源于stack exchange,提问作者glebtyanov
相关产品推荐
相关产品推荐

