【问题标题】:NUnit 3.0 and Assert.ThrowsNUnit 3.0 和 Assert.Throws
【发布时间】:2016-02-27 02:39:15
【问题描述】:

我正在使用 NUnit 3.0 编写一些单元测试,与 v2.x 不同,ExpectedException() 已从库中删除。

根据this 的回答,我绝对可以看到试图捕捉具体在测试中的哪个位置期望他们的系统抛出异常(而不是仅仅说“在测试中的任何位置”)的逻辑。

但是,我倾向于对我的 Arrange、Act 和 Assert 步骤非常明确,这使其成为一项挑战。

我曾经做过这样的事情:

[Test, ExpectedException(typeof(FormatException))]
public void Should_not_convert_from_prinergy_date_time_sample1()
{
    //Arrange
    string testDate = "20121123120122";

    //Act
    testDate.FromPrinergyDateTime();

    //Assert
    Assert.Fail("FromPrinergyDateTime should throw an exception parsing invalid input.");
}

现在我需要做类似的事情:

[Test]
public void Should_not_convert_from_prinergy_date_time_sample2()
{
    //Arrange
    string testDate = "20121123120122";

    //Act/Assert
    Assert.Throws<FormatException>(() => testDate.FromPrinergyDateTime());
}

在我看来,这并不可怕,但会混淆 Act 和 Assert。 (显然,对于这个简单的测试,它并不难遵循,但在较大的测试中可能更具挑战性)。

我有一个同事建议我完全摆脱 Assert.Throws 并做类似的事情:

[Test]
public void Should_not_convert_from_prinergy_date_time_sample3()
{
    //Arrange
    int exceptions = 0;
    string testDate = "20121123120122";

    //Act
    try
    {
        testDate.FromPrinergyDateTime();
    }
    catch (FormatException) { exceptions++;}

    //Assert
    Assert.AreEqual(1, exceptions);
}

在这里,我坚持使用严格的 AAA 格式,但代价是更加臃肿。

所以我的问题是 AAA 风格的测试人员:你会如何像我在这里尝试做的那样进行某种异常验证测试?

【问题讨论】:

  • 当被测方法没有参数时,Assert 可以这样简化: Assert.Throws(testDate.FromPrinergyDateTime) 或 Assert.That(testDate.FromPrinergyDateTime, Throws.TypeOf() );
  • 第二部分在我看来没有那么臃肿?

标签: c# unit-testing nunit nunit-3.0


【解决方案1】:

我知道你从哪里来,即使我不介意在这种情况下结合 Act/Assert 步骤。

我唯一能想到的是将实际委托(此处为FromPrinergyDateTime)存储到一个变量中作为“act”步骤,然后断言它:

[Test]
public void Should_not_convert_from_prinergy_date_time_sample2()
{
    //Arrange
    string testDate = "20121123120122";

    //Act
    ActualValueDelegate<object> testDelegate = () => testDate.FromPrinergyDateTime();

    //Assert
    Assert.That(testDelegate, Throws.TypeOf<FormatException>());
}

我知道“行动”这一步并不是真正在行动,而是定义了行动是什么。但是,它确实清楚地描述了正在测试的操作。

【讨论】:

  • 啊,这主意不错。我一直在纠结如何将两者分开。
  • 虽然还没有真正“演戏”。只是宣布你打算如何行动。
  • 这是一个很好的答案。我有一个follow-up question,我单独发布的。想看看吗?
【解决方案2】:

在 C# 7 中,还有另一个选项(尽管与现有答案非常相似):

[Test]
public void Should_not_convert_from_prinergy_date_time_sample2()
{
    void CheckFunction()
    {
        //Arrange
        string testDate = "20121123120122";

        //Act
        testDate.FromPrinergyDateTime();
    }

    //Assert
    Assert.Throws(typeof(Exception), CheckFunction);
}

Blog post on the subject

【讨论】:

  • 赞成,因为“你可以在 c# 中实际做到这一点”因素
【解决方案3】:

您可以在 NUnit 3 中创建自定义属性。这里是如何创建 [ExpectedException] 属性的示例代码。(ExpectedExceptionExample 显示如何为 NUnit 实现自定义属性) https://github.com/nunit/nunit-csharp-samples

【讨论】:

  • 这正是我要找的,谢谢你的链接!
  • [ExpectedException] 在 NUnit3 中已弃用。使用 Assert.That/Throws 机制。
  • @RvdK 你能告诉我 Assert.That 和 Assert.Throws 有什么区别吗.. 我真的不明白这两个语句之间的区别如下。两者都对我有用..但哪个更好用。 Assert.Throws&lt;DataLayerException&gt;(TestDelegate code, "Message");Assert.That(TestDelegate code, Is.TypeOf&lt;DataLayerException&gt;(), "Message");
  • @VikranthSanka Assert.That 具有更好的可读性,Assert.That 读起来更自然。但它也有其他一些好处:objectpartners.com/2013/09/18/…
猜你喜欢
  • 1970-01-01
  • 2018-07-05
  • 2013-02-07
  • 2014-01-04
  • 2011-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多