Moq/单元测试无法捕获异常,除非逐步执行代码

本文关键字:执行 代码 单元测试 捕获异常 Moq | 更新日期: 2023-09-27 18:26:30

我有一个单元测试,它需要一个Exception作为返回参数。

如果我通过调试器运行代码,并检查各种元素,它就能正常工作。如果我只是运行所有的测试,它不会。

这个问题一定与该方法是Async这一事实有关,就好像我删除了它作为expxted工作的各种Async元素一样。(我想是时间问题)

我的单元测试是;

  [TestMethod]
  [ExpectedException(typeof(System.AggregateException))]
  public void Service_GetDoc_ThrowsExceptionIfNull()
  {
        var nullRepository = new Mock<CCLDomainLogic.Repositories.DocRepository>();
        IDD emptyDoc = null;
        nullRepository
          .Setup<Task<CCLDomainLogic.DomainModels.Doc>>
          (x => x.GetDocAsync(It.IsAny<int>()))
          .Returns(() => Task<CCLDomainLogic.DomainModels.Doc>.Factory.StartNew(() => emptyDoc));
        DocService s = new DocService(nullRepository.Object);
        var foo = s.GetDocAsync(1).Result;
    }            

代码(缩写为)

    public async Task<Doc> GetDocAsync(int id)
    {
        Stopwatch timespan = Stopwatch.StartNew();
        try
        {
            ...                
            {
                var t = await Task.Run(() => _repository.GetDocAsync(id));
                ...
            }
            timespan.Stop();
            if (t == null)
            {
                throw new ArgumentNullException("DocService.GetDocAsync returned Null Document");
            }
        }
        catch (Exception e)
        {
            throw new Exception("Error in DocService.GetDocAsync", e);
        }
    }

那么,当运行async时,我该如何重新进行这个测试来捕捉异常呢。作为一个额外的问题,我可以修改我的单元测试,这样我就可以检查特定的异常,而不是聚合异常吗?

Moq/单元测试无法捕获异常,除非逐步执行代码

测试运行异步代码的原因,该代码在断言已经运行(或没有运行)之后执行。使用调试器只会给异步代码更多的工作时间。为了测试您的代码,您所要做的就是将MTest的返回类型更改为Task,并将wait添加到相关调用:

[TestMethod]
[ExpectedException(typeof(System.AggregateException))]
public async Task Service_GetDoc_ThrowsExceptionIfNull()
{
    var nullRepository = new Mock<CCLDomainLogic.Repositories.DocRepository>();
    IDD emptyDoc = null;
    nullRepository
        .Setup<Task<CCLDomainLogic.DomainModels.Doc>>(x => x.GetDocAsync(It.IsAny<int>()))
        .Returns(() => Task<CCLDomainLogic.DomainModels.Doc>.Factory.StartNew(() => emptyDoc));
    DocService s = new DocService(nullRepository.Object);
    var foo = await s.GetDocAsync(1).Result;
}