我如何检查“;没有出现异常“;在我的MSTest单元测试中
本文关键字:异常 我的 单元测试 MSTest 何检查 检查 | 更新日期: 2023-09-27 18:25:39
我正在为这个返回"void"的方法编写一个单元测试。我希望有一个案例,当没有抛出异常时,测试通过。我该如何用C#写?
Assert.IsTrue(????)
(我的猜测是这是我应该检查的方式,但"??"中包含了什么)
我希望我的问题足够清楚。
如果抛出异常,您的单元测试无论如何都会失败——您不需要放入特殊的断言。
这是少数几个完全没有断言的单元测试场景之一——如果引发异常,测试将隐式失败。
然而,如果你真的想为此写一个断言——也许是为了能够捕获异常并报告"预期没有异常,但得到了这个…",你可以这样做:
[Test]
public void TestNoExceptionIsThrownByMethodUnderTest()
{
var myObject = new MyObject();
try
{
myObject.MethodUnderTest();
}
catch (Exception ex)
{
Assert.Fail("Expected no exception, but got: " + ex.Message);
}
}
(上面是NUnit的一个例子,但MSTest也是如此)
在NUnit中,您可以使用:
Assert.DoesNotThrow(<expression>);
断言您的代码没有抛出异常。尽管即使没有断言,如果抛出异常,测试也会失败,但这种方法的价值在于,您可以区分测试中未满足的期望和错误,并且可以选择添加将显示在测试输出中的自定义消息。措辞良好的测试输出可以帮助您定位代码中导致测试失败的错误。
我认为添加测试以确保代码不会抛出异常是有效的;例如,假设您正在验证输入,并且需要将传入的字符串转换为long。有时字符串可能为null,这是可以接受的,因此您需要确保字符串转换不会引发异常。因此,将有代码来处理这种情况,如果您还没有为此编写测试,您将错过对重要逻辑部分的覆盖。
这个助手类用MSTest解决了我的问题。也许它也会刮伤你的。
[TestMethod]
public void ScheduleItsIneligibilityJob_HasValid_CronSchedule()
{
// Arrange
var factory = new StdSchedulerFactory();
IScheduler scheduler = factory.GetScheduler();
// Assert
AssertEx.NoExceptionThrown<FormatException>(() =>
// Act
_service.ScheduleJob(scheduler)
);
}
public sealed class AssertEx
{
public static void NoExceptionThrown<T>(Action a) where T:Exception
{
try
{
a();
}
catch (T)
{
Assert.Fail("Expected no {0} to be thrown", typeof(T).Name);
}
}
}
不要测试没有发生什么。这就像确保代码不会中断。这在某种程度上意味着,我们都在努力实现无中断、无bug的代码。你想为此写测试吗?为什么只有一种方法?你不希望所有的方法都经过测试,这样它们就不会抛出一些异常吗?沿着这条路走下去,您将为代码库中的每个方法获得一个额外的、伪的、断言较少的测试。它没有任何价值。
当然,如果您的需求是验证方法是否捕获异常,那么您可以测试它(或者稍微反转它;测试它是否没有抛出它应该捕获的东西)。
然而,一般的方法/实践保持不变——你不会为一些超出测试代码范围的人工/模糊需求编写测试("它有效"或"不抛出"的测试通常就是这样的例子——尤其是在方法的责任众所周知的情况下)。
简单地说,关注代码必须做的事情并进行测试。
我喜欢在每次测试结束时看到一个Assert.Whatever
,只是为了保持一致性。。。如果没有,我真的能确定那里不应该有吗?
对我来说,这就像放Assert.IsTrue(true);
一样简单
我知道我不是无意中把代码放在那里的,因此我应该很有信心快速浏览一下,这是预期的。
[TestMethod]
public void ProjectRejectsGappedVersioningByDefault() {
var files = new List<ScriptFile>();
files.Add(ScriptProjectTestMocks.GetVersion1to2());
files.Add(ScriptProjectTestMocks.GetVersion3to4());
Assert.Throws<ScriptProject.InvalidProjectFormatException>(() => {
var sut = new ScriptProject(files);
});
}
[TestMethod]
public void ProjectAcceptsGappedVersionsExplicitly() {
var files = new List<ScriptFile>();
files.Add(ScriptProjectTestMocks.GetVersion1to2());
files.Add(ScriptProjectTestMocks.GetVersion3to4());
var sut = new ScriptProject(files, true);
Assert.IsTrue(true); // Assert.Pass() would be nicer... build it in if you like
}
使用Xuit,您可以使用以下内容:
var exception = Record.Exception(() =>
MethodUnderTest());
Assert.Null(exception);
或异步操作
var exception = await Record.ExceptionAsync(async () =>
await MethodUnderTestAsync());
Assert.Null(exception);
我的朋友Tim告诉我ExpectedException。我真的很喜欢这个b/c,它更简洁,代码更少,而且非常明确地表明您正在测试异常。
[TestMethod()]
[ExpectedException(typeof(System.Exception))]
public void DivideTest()
{
int numerator = 4;
int denominator = 0;
int actual = numerator / denominator;
}
您可以在这里阅读更多关于它的信息:ExpectedException属性用法。
另一种对我有用的方法是将其存储在变量中并检查输出。
var result = service.Run()
Assert.IsFalse(result.Errors.Any())
using Moq;
using Xunit;
[Fact]
public void UnitTest_DoesNotThrow_Exception()
{
var builder = new Mock<ISomething>().Object;
//Act
var exception = Record.Exception(() => builder.SomeMethod());
//Assert
Assert.Null(exception);
}