71

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

基于这个答案,我绝对可以看到试图在测试中具体捕获一个期望他们的系统抛出异常的逻辑(而不是仅仅说“测试中的任何地方”)。

但是,我倾向于对我的 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 风格的测试人员:你将如何像我在这里尝试做的那样进行某种异常验证测试?

4

3 回答 3

68

我知道你来自哪里,即使我不介意在这种情况下结合 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>());
}

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

于 2015-11-24T15:23:10.287 回答
27

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

关于该主题的博客文章

于 2017-03-14T08:24:53.567 回答
6

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

于 2017-03-08T01:36:31.000 回答