我如何使用Assert(或其他测试类)来验证在使用MSTest/Microsoft.VisualStudio.TestTools.UnitTesting时抛出了异常?
当前回答
这是测试方法的一个属性…你不使用Assert。看起来是这样的:
[ExpectedException(typeof(ExceptionType))]
public void YourMethod_should_throw_exception()
其他回答
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);
}
既然您提到了使用其他测试类,那么比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用于异步方法测试。
查看nUnit文档中的例子:
[ExpectedException( typeof( ArgumentException ) )]
这取决于您使用的测试框架?
例如,在MbUnit中,您可以用一个属性指定预期的异常,以确保您得到的是真正预期的异常。
[ExpectedException(typeof(ArgumentException))]
我最喜欢的实现方法是编写一个名为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());
}
它的外观和行为更像单元测试语法的其余部分。
推荐文章
- 实体框架核心:在上一个操作完成之前,在此上下文中开始的第二个操作
- 如何为构造函数定制Visual Studio的私有字段生成快捷方式?
- 为什么Visual Studio 2015/2017/2019测试运行器没有发现我的xUnit v2测试
- 如何使用JSON确保字符串是有效的JSON。网
- AppSettings从.config文件中获取值
- 通过HttpClient向REST API发布一个空体
- 如何检查IEnumerable是否为空或空?
- 自动化invokerrequired代码模式
- 在c#代码中设置WPF文本框的背景颜色
- 在c#中,什么是单子?
- 单元测试反模式目录
- c#和Java中的泛型有什么不同?和模板在c++ ?
- c#线程安全快速(est)计数器
- 如何将此foreach代码转换为Parallel.ForEach?
- 如何分裂()一个分隔字符串到一个列表<字符串>