【问题标题】:ExpectedException Assert预期异常断言
【发布时间】:2013-12-10 12:07:27
【问题描述】:

我需要为下一个函数写一个单元测试,我看到我可以使用 [ExpectedException]

这是要测试的功能。

public static T FailIfEnumIsNotDefined<T>(this T enumValue, string message = null)
        where T:struct
    {
        var enumType = typeof (T);

        if (!enumType.IsEnum)
        {
            throw new ArgumentOutOfRangeException(string.Format("Type {0} is not an Enum, therefore it cannot be checked if it is Defined not have defined.", enumType.FullName));
        } 
        else if (!Enum.IsDefined(enumType, enumValue))
        {
            throw new ArgumentOutOfRangeException(string.Format("{1} Value {0} is not does not have defined value in Enum of type {0}. It should not be...", enumType.FullName, message ?? ""));
        }

        return enumValue;
    }

这里是测试应该抛出的异常的代码

    [TestMethod] 
    [ExpectedException(ArgumentOutOfRangeException(ArgumentException), "message")]
    public void FailIfEnumIsNotDefined_Check_That_The_Value_Is_Not_Enum()
    {
        // PREPARE
        // EXECUTE
        // ASSERT
    }

我也不知道必须为异常做出断言。

【问题讨论】:

  • 使用Assert.Throws() 而不是ExpectedException,因为如果测试方法代码的任何部分发生异常,此属性会使测试通过。 Assert.Throws 允许测试发生异常的代码的确切位置。
  • @sthotakura MSTest 没有 Assert.Throws 除非您编写自定义的,无论如何这是首选的 MSTest 异常处理。类似于 NUnit :) 我的答案中有一个链接
  • @Spock 我不知道,谢谢!
  • @sthotakura, Spock 我在我的回答中也为Throws 提供了一个示例实现:stackoverflow.com/a/45270837/67824。

标签: c# unit-testing testing expected-exception


【解决方案1】:

ExpectedException 只是断言测试方法会抛出指定类型的异常:

[TestMethod] 
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void FailIfEnumIsNotDefined_Check_That_The_Value_Is_Not_Enum()
{
    // PREPARE
    // EXECUTE
    // NO ASSERT!!
}

如果你想断言异常的其他参数,那么你应该在你的测试方法中使用try..catch:

[TestMethod]     
public void FailIfEnumIsNotDefined_Check_That_The_Value_Is_Not_Enum()
{
    // PREPARE

    try
    {
       // EXECUTE
       Assert.Fail()
    }
    catch(Exception exception)
    {        
        // ASSERT EXCEPTION DETAILS
    }
}

您可以编写自己的方法来断言抛出异常,以避免一遍又一遍地重复相同的测试代码:

public TException AssertCatch<TException>(Action action)
    where TException : Exception
{
    try
    {
        action();
    }
    catch (TException exception)
    {
        return exception;
    }

    throw new AssertFailedException("Expected exception of type " + 
                                    typeof(TException) + " was not thrown");
}

用法:

var exception = AssertCatch<ArgumentOutOfRangeException>(() => /* EXECUTE */);
Assert.AreEqual("foo", exception.Message);

【讨论】:

    【解决方案2】:

    用正确的异常消息断言异常被抛出:

    var ex = Assert.Throws<Exception>(() => _foo.DoSomething(a, b, c));
    Assert.That(ex.Message, Is.EqualTo("Your exception message"));
    

    【讨论】:

      【解决方案3】:

      您必须以不同的方式使用ExpectedException:

      [TestMethod]
      [ExpectedException(typeof(ArgumentOutOfRangeException))]
      public void MyTestSomething() 
      

      然后对您的测试进行编码,以便引发预期的异常。

      【讨论】:

        【解决方案4】:

        虽然ExpectedException 不能按原样使用来验证异常的消息,但您可以通过从ExpectedExceptionBaseAttribute 继承来实现自己的异常验证逻辑:

        通过实施您自己的预期异常验证。你可以 指定内置的附加信息和要求 ExpectedExceptionAttribute 类的方法无法处理,如 以下:

        • 验证异常状态。
        • 预期不止一种类型的异常。
        • 抛出错误类型的异常时显示自定义消息。
        • 控制阴性测试的结果。

        在你的情况下,它可能看起来像这样:

        public sealed class ExpectedExceptionMessageAttribute<T> : ExpectedExceptionBaseAttribute
        {
            readonly string _expectedMessage;
            public ExpectedExceptionMessageAttribute(string expectedMessage)
            {
                _expectedMessage = expectedMessage;
            }
        
            protected override void Verify(System.Exception exception)
            {
                // Handle assertion exceptions from assertion failures in the test method
                base.RethrowIfAssertException(exception);
        
                Assert.IsInstanceOfType(exception, typeof(T), "wrong exception type");
                Assert.AreEqual(_expectedMessage, exception.Message, "wrong exception message");
            }
        }
        

        话虽如此,我仍然倾向于使用直接的try-catch 方法,因为它更具体地说明了预计会引发异常的确切位置:

        public static void Throws<T>(Action action, Predicate<T> predicate = null) 
                            where T : Exception
        {
            try
            {
                action();
            }
            catch (T e)
            {
                if (predicate == null || predicate(e))
                {
                    return;
                }
        
                Assert.Fail($"Exception of type {typeof(T)} thrown as expected, but the provided predicate rejected it: {e}");
            }
            catch (Exception e)
            {
                Assert.Fail($"Expected exception of type {typeof(T)} but a different exception was thrown: {e}");
            }
        
            Assert.Fail($"No exception thrown, expected {typeof(T)}");
        }
        

        【讨论】:

          【解决方案5】:

          如果您使用 ExpectedException 属性,则不需要断言,实际上您的代码不应该能够到达断言。

          看: http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.expectedexceptionattribute.aspx

          如果你想确保抛出异常,你应该在应该抛出异常的操作之后放置一个 Assert.Fail(),在这种情况下,如果没有抛出异常,测试将失败。

          【讨论】:

            猜你喜欢
            • 2018-11-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-01-19
            • 1970-01-01
            • 1970-01-01
            • 2017-12-14
            相关资源
            最近更新 更多