【问题标题】:Test fails if an Exception is thrown in another part of the SUT (async flow)如果在 SUT 的另一部分(异步流)中抛出异常,则测试失败
【发布时间】:2023-03-28 14:36:02
【问题描述】:

我有这样的系统

class Sut
{
    IRepository _repo;

    public Sut(IRepository repo) { _repo = repo; }

    async Task Handle(Request request)
    {
         var entity  = new Entity(request.Id); //=> if Id is not ok the Entity throws Exception
    
         _repo.Save(entity);
    }
}

这是测试

[Fact]
public async Task Test_Save()
{
    Mock<IRepository> repositoryMock = new Mock<IRepository>();

    repositoryMock
        .Setup(repo => repo.Save(It.IsAny<Entity>()))
        .Returns(Task.CompletedTask);

    var sut = new Sut(repositoryMock.Object);

    /// Act
    Action action = async () => await sut.Handle(new Request { Id = default(Guid)});

    /// Assert 
    Assert.Throws<Exception>(action);
    repositoryMock.Verify(repo => repo.Save(It.IsAny<Entity>(), Times.Never);
}

所以它的作用是,Entity 对传递给它的默认Guid 进行检查。如果传递默认值,则会抛出异常。

抛出异常,但测试失败并显示此消息。

消息:Assert.Throws()

预期失败:typeof(System.Exception)

实际:(没有抛出异常)

测试从不调用

repositoryMock.Verify(repo => repo.Save(It.IsAny<Entity>(), Times.Never);

它将在这一行中断

为什么会这样以及如何解决这种情况?

Assert.Throws<Exception>(action);

更新

 public Entity(Guid id)
 {
     if (default(Guid) == id) throw new Exception("cannot have a default value for id");
     Id = id;
 }

【问题讨论】:

  • 你在控制Entity吗?
  • 显示Entity,因为它与语句if Id is not ok the Entity throws Exception有关
  • 好的,我想我看到了问题所在。 Action action 基本上是 async void,这意味着抛出的异常不会被捕获。
  • 我也尝试过不使用 Action 并删除 Assertion 部分,只留下 Verification,当我这样做时,我得到异常 Message: Sytem.Exception : cannot have a default value for id

标签: c# unit-testing testing moq


【解决方案1】:

Action action = async () =&gt; ... 基本上是async void,这意味着抛出的异常不会被捕获。

更改语法以使用Func&lt;Task&gt;Assert.ThrowsAsync

[Fact]
public async Task Test_Save() {
    //Arrange
    var repositoryMock = new Mock<IRepository>();

    repositoryMock
        .Setup(repo => repo.Save(It.IsAny<Entity>()))
        .Returns(Task.CompletedTask);

    var sut = new Sut(repositoryMock.Object);

    /// Act
    AsyncTestDelegate act = () => sut.Handle(new Request { Id = default(Guid)});

    /// Assert 
    await Assert.ThrowsAsync<Exception>(act);
    repositoryMock.Verify(repo => repo.Save(It.IsAny<Entity>(), Times.Never);
}

参考Assert.ThrowsAsync

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-27
    • 1970-01-01
    • 2018-11-21
    • 1970-01-01
    • 1970-01-01
    • 2017-02-19
    • 2017-03-13
    相关资源
    最近更新 更多