Moq.MockException测试失败:期望IMapper.Map调用1次却未执行
问题描述
Message: Moq.MockException:
Expected invocation on the mock once, but was 0 times: m => m.Map(AnnotationMasterRequest)
Performed invocations:MockIMapper:1 (m):
No invocations performed.
服务方法代码
public async Task<ServiceResponse<AnnotationMasterResponse>> CreateAnnotation(AnnotationMasterRequest annotationMasterRequest) { return await serviceResponseExceptionHandler.HandleAsync(async () => { var annotationMaster = _mapper.Map<AnnotationMaster>(annotationMasterRequest); annotationMaster.AnnotationMasterId = Guid.NewGuid(); var responseResult = await base.Insert(annotationMaster); return responseResult.DataResult; }, annotationMasterRequest); }
测试用例代码
public class AnnotationMasterServiceTests { private readonly Mock<IUnitOfWork> _unitOfWorkMock; private readonly Mock<IMapper> _mapperMock; private readonly Mock<IServiceResponseExceptionHandler> _exceptionHandlerMock; private readonly AnnotationMasterService _service; public AnnotationMasterServiceTests() { _unitOfWorkMock = new Mock<IUnitOfWork>(); _mapperMock = new Mock<IMapper>(); _exceptionHandlerMock = new Mock<IServiceResponseExceptionHandler>(); _service = new AnnotationMasterService( _unitOfWorkMock.Object, _mapperMock.Object, _exceptionHandlerMock.Object); } [Fact] public async Task CreateAnnotation_ShouldReturnSuccess_WhenValidRequest() { // Arrange var request = new AnnotationMasterRequest { AnnotationMasterName = "test" }; var annotationMaster = new AnnotationMaster(); var annotationMasterResponse = new AnnotationMasterResponse { /* populate fields */ }; // Create a mock ServiceResponse that returns a valid response, but we don't need to access internal properties. var serviceResponse = new ServiceResponse<AnnotationMasterResponse> { // Leave the internal properties (DataResult, Success, Message) as they are // Your test doesn't need to access them directly; we assume the ServiceResponse is set up correctly }; _mapperMock.Setup(m => m.Map<AnnotationMaster>(request)).Returns(annotationMaster); _exceptionHandlerMock.Setup(e => e.HandleAsync(It.IsAny<Func<Task<AnnotationMasterResponse>>>(), request)).ReturnsAsync(serviceResponse); // Act var result = await _service.CreateAnnotation(request); // Assert Assert.NotNull(result); Assert.Equal(serviceResponse.DataResult, result.DataResult); _mapperMock.Verify(m => m.Map<AnnotationMaster>(request), Times.Once); } }
Mapper代码
public class AnnotationMasterMapper : Profile { public AnnotationMasterMapper() { CreateMap<AnnotationMasterRequest, AnnotationMaster>(); CreateMap<AnnotationMaster, AnnotationMasterResponse>(); CreateMap<Annotation, AnnotationResponse>(); } }
问题原因
测试中对_exceptionHandlerMock的配置直接返回了预设的serviceResponse,完全没有执行传入的业务逻辑委托(也就是服务方法里包含_mapper.Map的那段代码),导致_mapper.Map从未被调用,触发了Moq的验证失败。
解决方案
1. 让ExceptionHandler的Mock执行传入的业务委托
修改_exceptionHandlerMock的Setup,使其实际执行传入的委托,模拟真实的ExceptionHandler行为:
// 替换原来的ExceptionHandler Setup _exceptionHandlerMock.Setup(e => e.HandleAsync(It.IsAny<Func<Task<AnnotationMasterResponse>>>(), It.IsAny<AnnotationMasterRequest>())) .ReturnsAsync(async (Func<Task<AnnotationMasterResponse>> func, AnnotationMasterRequest req) => { // 执行传入的业务逻辑委托 var responseData = await func(); // 包装成ServiceResponse返回(如果需要模拟异常处理的其他逻辑,也可以在这里添加) return new ServiceResponse<AnnotationMasterResponse> { DataResult = responseData }; });
2. 补充Mock基类Insert方法的行为
因为执行业务委托时会调用base.Insert,所以需要给_unitOfWorkMock补充对应的Setup(假设基类的Insert方法依赖IUnitOfWork):
// Arrange阶段添加: var insertedResponse = new ServiceResponse<AnnotationMasterResponse> { DataResult = annotationMasterResponse // 这里用你预设的AnnotationMasterResponse }; // 假设基类Insert最终调用_unitOfWork的某个方法,比如InsertAsync _unitOfWorkMock.Setup(u => u.InsertAsync(It.IsAny<AnnotationMaster>())) .ReturnsAsync(insertedResponse);
3. 调整Mapper的验证逻辑(可选)
如果不想严格匹配传入的request对象,可以用It.IsAny<AnnotationMasterRequest>()来放宽验证条件,避免因为对象引用不匹配导致的验证失败:
_mapperMock.Verify(m => m.Map<AnnotationMaster>(It.IsAny<AnnotationMasterRequest>()), Times.Once);
内容的提问来源于stack exchange,提问作者Yash Depani
相关产品推荐
相关产品推荐

