内部异常的单元测试

时间:2015-01-26 14:20:57

标签: c# entity-framework unit-testing

我正在使用Visual Studio的集成框架编写一些单元测试。我需要编写一些测试用例,在抛出适当的异常时传递。问题是我需要测试的异常是嵌套在更一般的异常中的内部异常。是否有一些简单的解决方案或我是否需要扩展整个功能。我目前正在使用[ExpectedException]属性,但在这种情况下它不会有太多好处。

我也很好奇当我们使用[ExpectedException]时会发生什么,而我们在测试中也有一些Assert逻辑。是否评估了条件(抛出异常并且Assert语句结果有效)或者在抛出正确的异常后测试立即通过?

5 个答案:

答案 0 :(得分:15)

不是一个完整的解决方案,但在Nunit中你可以做这种事情

 var ex = Assert.Throws<Exception>(() => thing.ThatThrows());
 Assert.That(ex.InnerException, Is.TypeOf<BadException>() );

也许你可以在你的测试框架中?

答案 1 :(得分:14)

如果您的框架不支持自定义投掷,您通常有两种选择:

  1. 自己实施
  2. 更改(或扩展)框架
  3. 我将从第二个解决方案开始。考虑使用FluentAssertions库。它允许你做这样的事情:

    Action deleteUser = () => usersRepository.Delete(new User { Id = null });
    
    deleteUser
        .ShouldThrow<UserNotFoundException>()
        .WithInnerException<ArgumentNullException>()
        .WithInnerMessage("User Id must have value");
    

    你仍然会使用Visual Studio测试框架,只是你将有一个额外的库,用于流畅的断言。

    另一方面,第一选择是更多的工作,因为通常情况下是手卷解决方案:

    try
    {
        usersRepository.Delete(new User { Id = null });
        Assert.Fail("Deleting user with null id should throw");
    }
    catch (UserNotFoundException ue)
    {
        Assert.AreEqual(ue.InnerException.Message, "User Id must have value");
    }
    

    ExpectedException属性替换为断言实际异常实例的自定义代码。就像我说的那样,这是更多的工作,但却有把戏。

答案 2 :(得分:3)

这是一个老问题,但我想与你们分享我自己的ExpectedInnerExceptionAttribute实现。也许对某人有用

public class ExpectedInnerExceptionAttribute : ExpectedExceptionBaseAttribute
 {
   public ExpectedInnerExceptionAttribute(Type exceptionType)
   {
     this.ExceptionType = exceptionType;
   }

   public Type ExceptionType { get; private set; }

   protected override void Verify(Exception ex)
   {
     if (ex != null && ex.InnerException != null
           && ex.InnerException.GetType() == this.ExceptionType)
      {
         return;
      }

       throw ex;
    }
}

您还可以扩展它以检查异常消息等,您只需要在Verify方法中添加自己的逻辑。

答案 3 :(得分:1)

对于单元测试,我目前使用FluentAssertions。自从我学会了以后,我就不想以任何其他方式断言。

对于断言异常,请查看documentation

的这一位

特别是这部分

Action act = () => subject.Foo2("Hello");

act.ShouldThrow<InvalidOperationException>()
     .WithInnerException<ArgumentException>()
     .WithInnerMessage("whatever")

答案 4 :(得分:0)

只需使用GetAwaiter()GetResult()来检查内部异常:

Assert.Throws<InnerException>(() => thing.GetAwaiter().GetResult());

例如

Assert.Throws<CommunicationException>(() => thing.GetAwaiter().GetResult());