c# - 如果 SUT 的另一部分(异步流程)抛出异常,则测试失败

标签 c# unit-testing testing moq

我有一个这样的系统

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。如果传递默认值,它将抛出异常。

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

Message: Assert.Throws()

Failure Expected: typeof(System.Exception)

Actual: (No exception was thrown)

测试从不调用

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;
 }

最佳答案

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

更改语法以使用 Func<Task>以及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

关于c# - 如果 SUT 的另一部分(异步流程)抛出异常,则测试失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53516495/

相关文章:

c# - EF Core - 如何使用值对象审计跟踪

c# - 在 WCF 中不使用 CallBack 将数据推送到客户端

testing - 在 Groovy 中如何模拟在另一个对象中实例化的对象?

c# - 如何像在 excel 列中一样创建字母表

javascript - 防止点击链接按钮时刷新页面

visual-studio-2010 - 单元测试在调试中通过,但在运行时挂起

reactjs - 如何模拟和测试 MaterialUI - makeStyles

java - 如何对同步代码进行单元测试

laravel - 发出 HTTP 请求并用数据填充它

javascript - 测试 Angular Controller : Controller Not Defined