NUnit 3.0和Assert.Throws


70

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

根据这个答案,我可以肯定地看到尝试专门捕获测试中期望系统抛出异常的地方的逻辑(而不是仅仅说“测试中的任何地方”)。

但是,我倾向于非常明确地说明我的“安排”,“行动”和“声明”步骤,因此这是一个挑战。

我曾经做过类似的事情:

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

在我看来,这并不可怕,但是却使《法案》和《断言》混为一谈。(显然,对于这个简单的测试,它并不难遵循,但是在大型测试中可能更具挑战性)。

我有一位同事建议我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风格的测试人员身上:您将如何像我在这里尝试的那样进行某种异常验证测试?


1
当测试方法没有参数时,可以这样简化Assert:Assert.Throws <FormatException>(testDate.FromPrinergyDateTime)或Assert.That(testDate.FromPrinergyDateTime,Throws.TypeOf <FormatException>());
user3285954 '16

第二部分看起来对我不那么肿?
安德鲁·戴

Answers:


66

即使在这种情况下我不介意将Act / Assert步骤组合在一起,我也知道您来自哪里。

我唯一能想到的就是将实际的委托(此处为FromPrinergyDateTime)存储到变量中作为“操作”步骤,然后对其进行断言:

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

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


啊,那真是个好主意。我开始迷恋如何将两者分开。
Killnine 2015年

2
仍然不是真正的“演戏”。只是宣布您打算如何行动。
JamesFaix

这是一个很好的答案。我对此有一个后续问题,我将其单独发布。想要看看吗?
Konrad Viltersten

26

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

关于该主题的博客文章


5
由于“您实际上可以在C#中执行此操作”因素而
投票

6

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


这正是我在寻找的东西,谢谢您的链接!
crabCRUSHERclamCOLLECTOR

在NUnit3中不推荐使用[ExpectedException]。使用Assert.That / Throws机制。
RvdK

@RvdK您能否让我知道Assert.That和Assert.Throws之间有什么区别。两者都对我有用。但是更好用。 Assert.Throws<DataLayerException>(TestDelegate code, "Message"); Assert.That(TestDelegate code, Is.TypeOf<DataLayerException>(), "Message");
VSanka '20年

@VikranthSanka Assert.Assert具有更好的可读性,读起来更自然。但这还具有其他一些好处:objectpartners.com/2013/09/18/…–
RvdK
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.