CSharp - 如何使用Assert来验证是否已引发异常?

  显示原文与译文双语对照的内容

如何使用 Assert ( 或者其他测试类) 验证是否已经引发异常?

时间:

对于"Visual Studio 团队测试",你似乎将ExpectedException属性应用于测试方法。

来自这里文档的示例: 一个单元测试演练,带有 Visual Studio 团队测试


[TestMethod]
[ExpectedException(typeof(ArgumentException),
"A userId of null was inappropriately allowed.")]
public void NullUserIdInConstructor()
{
 LogonInfo logonInfo = new LogonInfo(null,"P@ss0word");
}

通常你的测试框架会有一个答案。 但是如果它不够灵活,你可以总是这样做:


try {
 somethingThatShouldThrowAnException();
 Assert.Fail();//If it gets to this line, no exception was thrown
} catch (GoodException) { }

就像 @Jonas 指出的,这不适用于捕获基本异常:


try {
 somethingThatShouldThrowAnException();
 Assert.Fail();//raises AssertionException
} catch (Exception) {
//Catches the assertion exception, and the test passes
}

如果绝对必须捕获异常,则需要重新引发 Assert.Fail() 。 不过实际上,这是一个你不应该hand-writing这个签名;请检查你要测试的测试框架供选,或者看看是否能引发一个更有意义的异常。


catch (AssertionException) { throw; }

你应该能够根据你喜欢的--来调整这里方法,包括指定要捕获的异常种类。 如果你只期望某些类型,请用以下方法完成 catch 块:


} catch (GoodException) {
} catch (Exception) {
//not the right kind of exception
 Assert.Fail();
}

实现这里方法的首选方法是编写一个名为throw的方法,并使用它和其他任何断言方法一样。 不幸的是,.NET 不允许你编写静态扩展方法,所以你不能使用这个方法,就像它属于Assert类中的构建;只需将另一个叫做MyAssert或者类似的东西。 类类似于:


using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace YourProject.Tests
{
 public static class MyAssert
 {
 public static void Throws<T>( Action func ) where T : Exception
 {
 var exceptionThrown = false;
 try
 {
 func.Invoke();
 }
 catch ( T )
 {
 exceptionThrown = true;
 }

 if (!exceptionThrown )
 {
 throw new AssertFailedException(
 String.Format("An exception of type {0} was expected, but not thrown", typeof(T))
 );
 }
 }
 }
}

这意味着你的单元测试 如下所示:


 [TestMethod()]
 public void ExceptionTest()
 {
 String testStr = null;

 MyAssert.Throws<NullReferenceException>( () => testStr.ToUpper( ) );
 }

它看起来和行为更像你的单元测试 语法。

如果你使用的是最初没有 ExpectedException 属性的MSTest,你可以执行以下操作:


try 
{
 SomeExceptionThrowingMethod()
 Assert.Fail("no exception thrown");
}
catch (Exception ex)
{
 Assert.IsTrue(ex is SpecificExceptionType);
}

小心使用 ExpectedException,因为它可能会导致以下几个缺陷:

http://geekswithblogs.net/sdorman/archive/2009/01/17/unit-testing-and-expected-exceptions. aspx

还有这里:

http://xunit.codeplex.com/Wiki/View.aspx?title=Comparisons#note1

如果你需要测试异常,那么对方法的影响就越少。 你可以使用try尝试 {act/fail} 捕捉 {assert} 方法,该方法对于不支持除ExpectedException之外的异常测试的框架很有用。

在所有其它的错误,和improved,更好的替代方法是使用 xUnit.NET, 这是一种非常现代,前瞻性和可以扩展单元测试框架,这个框架已经 learned. 一个改进是断言。抛出,它提供了一个更好的语法来断言异常。

你可以在CodePlex上找到 xUnit.NET: http://www.codeplex.com/xunit

我用HelperMethod来代替。

磅测试


[TestMethod]
public void AccountRepository_ThrowsExceptionIfFileisCorrupt()
{
 var file = File.Create("Accounts.bin");
 file.WriteByte(1);
 file.Close();

 IAccountRepository repo = new FileAccountRepository();
 TestHelpers.AssertThrows<SerializationException>(()=>repo.GetAll()); 
}

HelperMethod


public static TException AssertThrows<TException>(Action action) where TException : Exception
 {
 try
 {
 action();
 }
 catch (TException ex)
 {
 return ex;
 }
 Assert.Fail("Expected exception was not thrown");

 return null;
 }

这是测试方法的属性。。 你不使用断言。如下所示:


[ExpectedException(typeof(ExceptionType))]
public void YourMethod_should_throw_exception()

如果你使用 NUNIT,你可以执行如下操作:


Assert.Throws<ExpectedException>(() => methodToTest());

自身提供的helper 上面 @Richiban 伟大工程除了它不处理这种情况,并且将引发异常,但不是所需的类型。 以下地址:


using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace YourProject.Tests
{
 public static class MyAssert
 {
///<summary>
///Helper for Asserting that a function throws an exception of a particular type.
///</summary>
 public static void Throws<T>( Action func ) where T : Exception
 {
 Exception exceptionOther = null;
 var exceptionThrown = false;
 try
 {
 func.Invoke();
 }
 catch ( T )
 {
 exceptionThrown = true;
 }
 catch (Exception e) {
 exceptionOther = e;
 }

 if (!exceptionThrown )
 {
 if (exceptionOther!= null) {
 throw new AssertFailedException(
 String.Format("An exception of type {0} was expected, but not thrown. Instead, an exception of type {1} was thrown.", typeof(T), exceptionOther.GetType()),
 exceptionOther
 );
 }

 throw new AssertFailedException(
 String.Format("An exception of type {0} was expected, but no exception was thrown.", typeof(T))
 );
 }
 }
 }
}

查看 nUnit文档 。txt以了解以下示例:


[ExpectedException( typeof( ArgumentException ) )]

...