我如何使用Assert(或其他测试类)来验证在使用MSTest/Microsoft.VisualStudio.TestTools.UnitTesting时抛出了异常?
当前回答
Even though this is an old question, I would like to add a new thought to the discussion. I have extended the Arrange, Act, Assert pattern to be Expected, Arrange, Act, Assert. You can make an expected exception pointer, then assert it was assigned to. This feels cleaner than doing your Asserts in a catch block, leaving your Act section mostly just for the one line of code to call the method under test. You also don't have to Assert.Fail(); or return from multiple points in the code. Any other exception thrown will cause the test to fail, because it won't be caught, and if an exception of your expected type is thrown, but the it wasn't the one you were expecting, Asserting against the message or other properties of the exception help make sure your test won't pass inadvertently.
[TestMethod]
public void Bar_InvalidDependency_ThrowsInvalidOperationException()
{
// Expectations
InvalidOperationException expectedException = null;
string expectedExceptionMessage = "Bar did something invalid.";
// Arrange
IDependency dependency = DependencyMocks.Create();
Foo foo = new Foo(dependency);
// Act
try
{
foo.Bar();
}
catch (InvalidOperationException ex)
{
expectedException = ex;
}
// Assert
Assert.IsNotNull(expectedException);
Assert.AreEqual(expectedExceptionMessage, expectedException.Message);
}
其他回答
有一个很棒的库叫做NFluent,它可以加速和简化你编写断言的方式。
编写抛出异常的断言非常简单:
[Test]
public void given_when_then()
{
Check.ThatCode(() => MethodToTest())
.Throws<Exception>()
.WithMessage("Process has been failed");
}
我最喜欢的实现方法是编写一个名为Throws的方法,并像使用其他Assert方法一样使用它。不幸的是,.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属性更好的选择是使用Shoudly的Should.Throw。
Should.Throw<DivideByZeroException>(() => { MyDivideMethod(1, 0); });
假设我们有一个需求,客户必须有一个地址才能创建订单。如果不是,CreateOrderForCustomer方法应该导致一个ArgumentException。那么我们可以这样写:
[TestMethod]
public void NullUserIdInConstructor()
{
var customer = new Customer(name := "Justin", address := null};
Should.Throw<ArgumentException>(() => {
var order = CreateOrderForCustomer(customer) });
}
这比使用ExpectedException属性更好,因为我们明确了应该抛出错误的内容。这使得测试中的需求更加清晰,并且在测试失败时更容易诊断。
注意这里还有一个Should。ThrowAsync用于异步方法测试。
MSTest (v2)现在有一个Assert。ThrowsException函数,可以像这样使用:
Assert.ThrowsException<System.FormatException>(() =>
{
Story actual = PersonalSite.Services.Content.ExtractHeader(String.Empty);
});
您可以使用nuget: install - package MSTest安装它。TestFramework
你可以从Nuget下载一个包,使用:PM> Install-Package MSTestExtensions将Assert.Throws()语法以nUnit/xUnit的风格添加到MsTest。
高级指令:从BaseTest下载程序集并继承,您可以使用Assert.Throws()语法。
Throws实现的主要方法如下所示:
public static void Throws<T>(Action task, string expectedMessage, ExceptionMessageCompareOptions options) where T : Exception
{
try
{
task();
}
catch (Exception ex)
{
AssertExceptionType<T>(ex);
AssertExceptionMessage(ex, expectedMessage, options);
return;
}
if (typeof(T).Equals(new Exception().GetType()))
{
Assert.Fail("Expected exception but no exception was thrown.");
}
else
{
Assert.Fail(string.Format("Expected exception of type {0} but no exception was thrown.", typeof(T)));
}
}
披露:我整理了这个包。
更多信息:http://www.bradoncode.com/blog/2012/01/asserting-exceptions-in-mstest-with.html
推荐文章
- dynamic (c# 4)和var之间的区别是什么?
- 如何直接从测试驱动程序调用自定义的Django manage.py命令?
- Visual Studio: ContextSwitchDeadlock
- 如何重置笑话模拟函数调用计数之前,每次测试
- 返回文件在ASP。Net Core Web API
- 自定义HttpClient请求头
- 如果我使用OWIN Startup.cs类并将所有配置移动到那里,我是否需要一个Global.asax.cs文件?
- VS2013外部构建错误"error MSB4019: The imported project <path> was not found"
- 从另一个列表id中排序一个列表
- 等待一个无效的异步方法
- 无法加载文件或程序集…参数不正确
- c#中枚举中的方法
- 如何从字符串中删除新的行字符?
- 如何设置一个默认值与Html.TextBoxFor?
- 检查属性是否有属性