【问题标题】:How do I check "no exception occurred" in my MSTest unit test?如何在我的 MSTest 单元测试中检查“未发生异常”?
【发布时间】:2012-03-14 02:29:54
【问题描述】:

我正在为这个返回“void”的方法编写单元测试。我想有一种情况,即在没有抛出异常的情况下测试通过。我如何用 C# 编写它?

Assert.IsTrue(????)

(我猜这是我应该检查的方式,但是“???”中的内容)

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

【问题讨论】:

  • 你使用的是 MSTest 还是 NUnit?
  • 在 MSTest 中未捕获的异常将自动导致测试失败。您是否要考虑捕获的异常?
  • 您可以查找“try-catch for C#”,它将指导您如何处理抛出或未抛出的异常。
  • 如果是 NUnit,请查看 Assert.That( lambda ).Throws.Nothing (尽管我认为最近发生了变化)

标签: c# unit-testing exception mstest


【解决方案1】:

对我有用的另一种方法是将其存储在变量中并检查输出。

var result = service.Run()
Assert.IsFalse(result.Errors.Any())

【讨论】:

    【解决方案2】:

    我的朋友 Tim 告诉我关于 ExpectedException。我真的很喜欢这个 b/c,它更简洁,代码更少,并且非常明确地表明您正在测试异常。

    [TestMethod()]
    [ExpectedException(typeof(System.Exception))]
    public void DivideTest()
    {
        int numerator = 4;
        int denominator = 0;
        int actual = numerator / denominator;
    }
    

    您可以在此处阅读更多相关信息:ExpectedException Attribute Usage

    【讨论】:

    • OP 要求没有例外。
    • 我将把这个答案留在这里。我在谷歌搜索如何测试异常时发现了这个问题,我认为这个答案需要在这里。 OP 在 7 年前回答了他们的问题。即使是我认为其他答案的链接也是有帮助的。
    • 好老蒂姆。 ?
    【解决方案3】:

    我喜欢在每次测试结束时看到一个Assert.Whatever,只是为了保持一致性...没有一个,我真的可以确定那里不应该有一个吗?

    对我来说,这就像输入Assert.IsTrue(true); 一样简单

    知道我没有不小心把那个代码放在那里,因此我应该有足够的信心快速浏览一下,这符合预期。 p>

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

    【讨论】:

    • 不一样。如果您的代码抛出异常,则不会触发任何断言,并且您的测试运行将失败。你想通过断言一个条件来挂钩到测试框架。
    【解决方案4】:

    这个助手类用 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);
            }
        }
    }
    

    【讨论】:

    • @Remco Beurskens - 在 NoExceptionThrown 末尾添加一般 catch { } 将抑制其他错误,这不是该方法的预期结果。这不是抑制所有异常的通用方法。只有在抛出已知类型的异常时才会失败。
    • 这已经过时了,但是Assert 有一个单例属性访问器,That 可以用作扩展方法的钩子。使用Assert.That.DoesNotThrow() 而不是AssertEx.DoesNotThrow() 可能更简洁,更容易被发现。这只是一个意见。
    【解决方案5】:

    在 NUnit 中,你可以使用:

    Assert.DoesNotThrow(<expression>); 
    

    断言您的代码不会引发异常。尽管即使周围没有 Assert,如果抛出异常,测试也会失败,但这种方法的价值在于您可以区分未满足的期望和测试中的错误,并且您可以选择添加自定义消息将显示在您的测试输出中。措辞良好的测试输出可以帮助您定位代码中导致测试失败的错误。

    我认为添加测试以确保您的代码不会抛出异常是有效的;例如,假设您正在验证输入并需要将传入的字符串转换为长字符串。可能有字符串为空的情况,这是可以接受的,所以要确保字符串转换不会抛出异常。因此将有代码来处理这种情况,如果您没有为它编写测试,您将错过对重要逻辑的覆盖。

    【讨论】:

    • 明确的 DoesNotThrow 很好。如果您习惯于在测试中看到 Assert.*,您可能会认为对方很懒惰而忘记了。
    • 在 vstest 或 mstest 中是否有任何等价物?
    • @DanCsharpster,我认为至少在 MSTest 中没有 - 当我过去在 MSTest 中需要此功能时,我做过这样的事情:public class TestBase { //believe me, I don't like this anymore than you do. protected void AssertDoesNotThrow(Action action, string message) { try { action(); } catch (Exception) { Assert.Fail(message); } } }跨度>
    • @Clarkeye,这是一个有趣的想法。谢谢!希望他们能在未来的版本中学会更好地复制 NUnit。我也想过在 vstest 和 NUnit 之间写一个适配器。
    • @DanCsharpster,您可能想看看流利的断言,它对 ShouldThrow 和 ShouldNotThrow 有很好的支持:github.com/dennisdoomen/fluentassertions/wiki#exceptions。文档说它与 MSTest 兼容(尽管我只将它与 XUnit 和 NUnit 一起使用)。可能不会做任何你想做的事情,但你可以将它与 MSTest 断言混合使用。
    【解决方案6】:

    不要测试 doesn't happen 的东西。这就像确保代码不会中断。这有点暗示,我们都在努力争取不破坏、没有错误的代码。你想为此编写测试吗?为什么只有一种方法?您不希望您的所有方法都经过测试以确保它们不会引发异常吗?沿着这条路,您最终会为代码库中的每个方法一个额外的、虚拟的、无断言的测试。它没有任何价值。

    当然,如果您的要求是验证方法是否捕获异常,您确实要测试它(或稍微颠倒一下;测试它不会抛出什么应该抓住)。

    但是,一般方法/实践保持不变 - 您不会为超出测试代码范围的一些人为/模糊要求编写测试(并且测试“它有效”或“不会抛出”通常是一个这样的例子 - 特别是在方法的职责众所周知的情况下)。

    简单地说 - 专注于您的代码必须做什么并为此进行测试。

    【讨论】:

    • -1 我可以想到需要并且不抛出异常的积极功能。对于一个 - 其工作是处理异常的方法,记录它们并采取行动 - 而不进一步抛出异常。您提出了一个很好的一般性观点 - 但随后以绝对的方式说话,就好像它总是正确的一样。
    • @RobLevine:我理解您的示例,并且确实意识到您在这种情况下编写测试。然而,正如您所注意到的,我的观点确实是关于更一般的实践 - 可以说,测试您的代码应该做什么而不是测试您的代码不做什么。我已经改写了我的帖子,以便我的观点更清晰,更接近我的想法。也让您有机会重新考虑您的投票。感谢您的澄清,抱歉延迟回复。
    • 已删除反对票 - 下次反对票我不会那么高兴!
    • 在我们的项目中,我们有 htmlvalidator 类,如果 html 无效则抛出异常。例如,当用户在丰富的组合中输入(使用控制台)javascript 时。因此,在我的案例代码中,我的代码所做的是不抛出异常(白名单方法),我需要对此进行测试。
    • 不同意这个答案。有时在特定场景下测试某些东西的缺失可能是一个有效的测试。
    【解决方案7】:

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

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

    但是,如果您确实想为此编写一个断言 - 也许是为了能够捕获异常并报告“预期没有异常但得到了这个......”,您可以这样做:

    [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 也是如此)

    【讨论】:

    • 显然你不应该去捕捉这样的异常来保持这种情况。
    • 只有在抛出未捕获的异常时测试才会失败。依赖于异常处理程序中的代码,单元测试可能会通过。
    • 对Unittest女士有用,所以Unittest中没有Assert.DoesNotThrow(()方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-22
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多