You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Moq严格模式调用失败:测试Post方法返回CreatedAtRoute失败

问题分析与解决方案

错误原因

你遇到的Moq.MockException是因为Moq的Strict模式要求所有对Mock对象的调用必须提前设置对应的Setup。当前有两个核心问题:

  1. 你为IBookRepository.AddBook设置的Setup仅匹配特定的Book实例,但Post方法中会通过convertDbModelToInputViewModel生成新的Book对象,导致调用无法命中Setup。
  2. 错误信息提到的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 21:55:14