我如何检查“;没有出现异常“;在我的MSTest单元测试中

本文关键字:异常 我的 单元测试 MSTest 何检查 检查 | 更新日期: 2023-09-27 18:25:39

我正在为这个返回"void"的方法编写一个单元测试。我希望有一个案例,当没有抛出异常时,测试通过。我该如何用C#写?

Assert.IsTrue(????)

(我的猜测是这是我应该检查的方式,但"??"中包含了什么)

我希望我的问题足够清楚。

我如何检查“;没有出现异常“;在我的MSTest单元测试中

如果抛出异常,您的单元测试无论如何都会失败——您不需要放入特殊的断言。

这是少数几个完全没有断言的单元测试场景之一——如果引发异常,测试将隐式失败。

然而,如果你真的想为此写一个断言——也许是为了能够捕获异常并报告"预期没有异常,但得到了这个…",你可以这样做:

[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);
}