Moq严格模式调用失败:测试Post方法返回CreatedAtRoute失败
问题分析与解决方案
错误原因
你遇到的Moq.MockException是因为Moq的Strict模式要求所有对Mock对象的调用必须提前设置对应的Setup。当前有两个核心问题:
- 你为
IBookRepository.AddBook设置的Setup仅匹配特定的Book实例,但Post方法中会通过convertDbModelToInputViewModel生成新的Book对象,导致调用无法命中Setup。 - 错误信息提到的
IEventRepository.AddEvent说明你的BooksController可能依赖了IEventRepository,但测试中未为该Mock设置对应方法的Setup。
解决步骤
1. 修正IBookRepository.AddBook的匹配逻辑
Moq默认按对象引用匹配调用,你需要修改Setup来匹配任意Book实例,或者验证传入对象的属性是否符合预期:
// 替换原有的Setup,匹配任意Book对象 this.mockBookRepository.Setup(s => s.AddBook(It.IsAny<Book>())).Returns(1);
如果需要验证传入的Book属性正确性,可以在Verify时添加条件判断:
this.mockBookRepository.Verify(v => v.AddBook(It.Is<Book>(b => b.Name == books.Name && b.Author == books.Author && b.Publication == books.Publication && b.TotalPages == books.TotalPages )), Times.Once);
2. 处理IEventRepository的未Setup调用
检查BooksController的构造函数,如果存在IEventRepository依赖,需要在测试初始化时创建并Setup对应的方法:
private Mock<IEventRepository> mockEventRepository; public override void TestSetup() { mockBookRepository = this.CreateAndInjectMock<IBookRepository>(); // 添加IEventRepository的Mock创建与Setup mockEventRepository = this.CreateAndInjectMock<IEventRepository>(); mockEventRepository.Setup(s => s.AddEvent(It.IsAny<Event>())).Returns(true); // 根据实际返回值调整 Target = new BooksController(mockBookRepository.Object, mockEventRepository.Object); }
3. 可选:关闭Strict模式(不推荐)
如果不需要严格验证所有调用,可以在创建Mock时使用Loose模式(默认就是Loose,若你手动设置了Strict则修改):
mockBookRepository = new Mock<IBookRepository>(MockBehavior.Loose);
修正后的完整测试用例
[Fact] public void AddBook_ReturnCreatedAtRoute() { // 避免AutoFixture递归异常 var fixture = new Fixture(); fixture.Behaviors.RemoveAll(b => b is ThrowingRecursionBehavior); fixture.Behaviors.Add(new OmitOnRecursionBehavior(1)); var books = fixture.Create<Book>(); // 设置匹配任意Book实例的Setup this.mockBookRepository.Setup(s => s.AddBook(It.IsAny<Book>())).Returns(1); // Act BookInputModel booksViewModel = convertDbModelToInputModel(books); var actual = Target.Post(booksViewModel); // Assert var actionResult = Assert.IsType<ObjectResult>(actual); Assert.Equal((int)HttpStatusCode.Created, actionResult.StatusCode); // 验证AddBook被调用一次,且属性匹配 this.mockBookRepository.Verify(v => v.AddBook(It.Is<Book>(b => b.Name == books.Name && b.Author == books.Author && b.Publication == books.Publication && b.TotalPages == books.TotalPages )), Times.Once); }
内容的提问来源于stack exchange,提问作者SpinningTruck
相关产品推荐
相关产品推荐

