在NUnit

时间:2019-07-11 14:58:21

标签: c# unit-testing exception nunit

我有一个方法,它接受一个JSON对象,并使其经过多个处理阶段,并在每个阶段更新数据库中的值。我们希望这种方法具有容错能力,并确定所需的行为将是:如果任何处理阶段失败,则将错误记录到数据库中,并继续进行下一阶段的处理,而不是中止。

我刚刚对其中一个处理步骤的行为进行了几处更改。然后,我运行了我们的单元测试套件,期望由于新行为而导致多个测试失败,并指出潜在的问题区域。相反,测试全部通过。

调查后,我意识到测试所依据的模拟数据不包含对于新行为重要的某些关键值。实际上,这些测试在运行时就抛出了异常,但是却捕获并处理了这些异常-并且,由于这些测试未在启用记录器的情况下运行,因此它们被完全抑制了。因此,新代码不会以导致测试失败的方式更改数据,因为它只是默默地出错。

这似乎是单元测试要解决的问题,并且它们没有显示任何痕迹意味着他们没有达到目的。有什么方法可以使用NUnit断言即使处理了异常,也不会抛出任何异常?或者,是否有一种明智的重构方法可以更好地暴露此问题?

(使用C#,但问题似乎与语言无关)

1 个答案:

答案 0 :(得分:0)

首先,在您所描述的场景中,是否存在异常是次要的。如果编写代码以在捕获和处理异常的同时产生期望的结果,那么测试该结果(无论是返回值还是其他效果)是最重要的。

如果您没有看到的异常导致该结果不正确,那么测试正确的结果将始终能够发现问题。如果您不知道预期的结果,而仅对是否处理异常感兴趣,那您就错了。我们永远无法根据是否抛出异常来确定任何事物是否正常工作。

此外,这是测试您的代码是否正在捕获和记录本来无法观察到的异常的方法:

如果要注入看起来像这样的记录器:

public interface ILogger
{
    void LogError(Exception ex);
    void LogMessage(string message);
}

...然后,一种简单的方法是创建一个用于存储异常的测试双,以便您可以检查它并查看记录的内容。

public class ListLoggerDouble : ILogger
{
    public List<Exception> Exceptions = new List<Exception>();
    public List<string> Messages = new List<string>();

    public void LogError(Exception ex)
    {
        Exceptions.Add(ex);
    }

    public void LogMessage(string message)
    {
        Messages.Add(message);
    }
}

执行完要测试的方法后,可以断言一个集合包含您期望的异常或消息。如果您希望的话,您也可以验证其中没有一个,尽管如果您要测试的结果正确,这似乎是多余的。


我不会创建引发异常的记录器,然后编写测试以检查引发异常的测试器。这使得您的代码看起来像预期的行为是引发异常,这与它的行为完全相反。测试可以帮助我们记录预期的行为。另外,如果您想验证自己是否捕获并记录了两个异常,该怎么办?