【问题标题】:With Nunit, how to test if a method has caught an exception?使用 Nunit,如何测试方法是否捕获了异常?
【发布时间】:2016-01-21 12:17:59
【问题描述】:

我有一种方法可以将数据保存在我的数据库(C# 和 Mysql)中。我正在使用 MVP 模型,所以它的作用是在 Presenter 中保存 > 在服务中保存 > 在管理器中保存 > 在 dao 中保存。我在管理器中进行数据完整性控制。

我想测试我的演示者。第一次保存测试是用不正确的值完成的,以检查我的经理是否抛出异常。 问题是我的演示者捕获了这个异常,所以我不能使用Assert.Throws<Exception>(() => {DoSave();}),因为 Assert 没有看到异常。 NUnit 中是否有一个 Assert 来检查是否在测试代码中引发了异常而没有到达测试本身?

简化,看起来像这样: (主持人)

    private void SaveData()
    {
            try
            {
                //Calls service who calls manager who checks data then call DAO to save.
                if (MyService.SaveData(currentData, ReferentielType.ENEG))
                {
                    //Success
                }
                else
                {
                    //Failure
                }
            }
            //Thrown by the manager if the data are incorrect
            catch (DataInvalidException ex)
            {
                // log exception as error
                TraceHelper.TraceError(ex, "The data {0} is not correct", currentData.Code);

                // send a message to user
                MessageContainer.Instance.SendErrorMessage("DataInvalid", BusinessError.DataInvalid, currentData.Code);
            }
        }
    }

还有我的测试:

[Test]
    public void UpdateDataTest()
    {
        //Test setup 
        //making fake data
        //When the var etatDuTest is different from 0, it means some of the data are invalid

        //Instance of the presenter
        MockView view = new MockView();
        PresenterToTest presenter = new PresenterToTest(view);

        //Testing with invalid values
        //bad label
        ((MockView)((IView)presenter.View)).etatDuTest = 1;
        Assert.Throws<DataInvalidException>(() => { ((MockView)((IView)presenter.View)).RaiseSaveDataClicked(); });
        //Bad num eva
        ((MockView)((IView)presenter.View)).etatDuTest = 2;
        Assert.Throws<DataInvalidException>(() => { ((MockView)((IView)presenter.View)).RaiseSaveDataClicked(); });

        //Testing with everything OK
        //Tout est bon logiquement.
        ((MockView)((IView)presenter.View)).etatDuTest = 0;
        ((MockView)((IView)presenter.View)).RaiseSaveDataClicked();

    }

【问题讨论】:

  • MyService.SaveData(currentData, ReferentielType.ENEG)可以抛出Exception吗?
  • 而不是断言已经引发了异常(您将无法检查),您应该确保当您的 CoclicoInvalidException 类中有 CoclicoInvalidException 并且TraceErrorMessageContainter 被正确调用。为了确保Manager 正确地抛出异常,它应该有它自己的测试类,异常不会在您的业务逻辑中处理。
  • @StephenRoss 是的,我已经编写了管理器测试,但我想测试我的应用程序的另一层,以确保捕获到异常。
  • 因此,一种解决方法可能是测试MyService.SaveData(currentData, ReferentielType.ENEG) 抛出ColicoInvalidException,然后测试SaveData 不会抛出它。显然使用相同的参数。请注意,这并不是一个真正干净的解决方案。使用delegate 可能会更干净
  • @nivolas 在这种情况下,正如我所说,您要确保使用适当的参数正确调用 TraceHelper.TraceError。并且 MessageContainer.Instance.SendErrorMessage 使用适当的参数正确调用。这是为了测试您是否正确处理了异常,您无需在测试中检查它是否已被抛出,因为您将验证(或断言)您的对象已被正确调用(取决于您如何模拟它们)。

标签: c# unit-testing exception nunit


【解决方案1】:

测试是否已捕获异常本身就是一个毫无意义的测试。您应该测试 catch 块中发生的情况,这将验证是否捕获了异常。

如果您可以验证您的 MessageContainer.Instance 是否有该 DataInvalid 错误消息,那确实是您的最佳选择。

【讨论】:

  • 我没有想到MessageContainer,因为我专注于捕获异常itelsf,但你是对的。至于测试捕获的异常,我发现它很有用,因为它可以确保没有人根据他的需要修改数据完整性控制(因为它是由多个演示者调用的方法,它可以被修改,我们不希望那样,它是一个非回归测试而不是单元测试)
  • 就像我说的那样,测试是否捕获了异常是没有意义的,您真正关心的是,当 SaveData 抛出异常时,它会执行 catch 中的行为。任何人都可以重写它,但是只要 SaveData 抛出异常后它仍然执行该行为,您就不必担心。你不能通过为它编写测试来阻止人们重写代码,事实上这根本不是测试的目的。他们在那里确保人们可以更改方法,但确保无论如何,当 SaveData 抛出异常 Instance.SendErrorMessage 被调用
  • 我的看法(我可能错了,但这就是我看到我的测试的方式)是如果有人删除控件或更改它(假设有人将字符串长度控件从 6 个字符更改为 8 个字符) ,保存可能会起作用或可能会引发另一个异常,因此测试将失败。最后这就是我想要的,知道测试何时无法检查原因并决定做什么(更改我的测试或更改完整性控制)
猜你喜欢
  • 2015-11-02
  • 2014-08-14
  • 1970-01-01
  • 2016-06-16
  • 2020-11-10
  • 1970-01-01
  • 2013-10-08
  • 2011-07-31
  • 1970-01-01
相关资源
最近更新 更多