如何对未定义的行为进行单元测试?

时间:2014-07-07 11:39:31

标签: c# unit-testing nunit

我有一组相关的类,它们采用各种输入并产生预期的输出。这些是单元测试的理想低级候选者,并且所有这些都适用于有效输入。

难度来自无效输入,特别是在尝试从未添加的集合中删除项目时,我们目前有未定义的行为:某些类只会产生垃圾结果(GIGO 1 胜利)但有些人会抛出异常(可能是KeyNotFoundException)。

鉴于这些无效输入没有有效,一致的行为(这意味着某些内容在其他地方被错误配置,并且无法产生明智的结果),并且我们的API明确指出调用者必须只删除他们的内容补充说,这怎么能反映在我们的单元测试中?

它显然不能成为“测试”,因为没有明确的行为(如果我们的任何一个应用程序的实现在将来发生变化,那么简单地记录我们当前的行为将是脆弱的),但我希望有一种方法可以排除一些热心的团队成员未来可能会在不了解潜在问题的情况下添加一个。

其中一个的单元测试方法目前看起来像这样:

[TestCase("1", "2", "1", ExpectedResult = "|2|")]
[TestCase("1", "2", "2", ExpectedResult = "|1|")]
public object InsertTwoDeleteOne(string insertedValue1,
                                 string insertedValue2,
                                 string deletedValue1)
{
    // Apply tests here
}

我可以看到处理这个问题的两种方法是在测试方法中添加显式代码:

    if (deletedValue1 != insertedValue1 &&
        deletedValue1 != insertedValue2)
    {
        Assert.Fail("Invalid inputs");
    }

但这是“脱节”并且在其他测试用例中不太容易看到,或者添加TestCase纯粹用于文档说“不要运行此”,如下所示:

[TestCase("1", "2", "3", Ignore = true, Reason = "Invalid inputs")]

但是这会导致“跳过测试”结果不整洁。

有什么更好的吗?


[编辑]有问题的API是一个公共接口,我们在产品中有很多实现:正是这些实现我正在更新测试的过程中。但是,安装可以自己编写自己的实现作为插件(通过创建自己的程序集,实现自己的对象,并通过配置实例化),因此我们的框架将在调用之前确保数据有效。

在我们当前的模型中,安装不太可能重用对象并从他们自己的代码中调用它们。

我们选择不关心验证每个对象中的数据的原因有两个:

  1. 在我们的默认产品配置中,它将始终接收已由呼叫者验证过的数据。
  2. 性能:我们在这里存储了大量数据 - 目前仅限于100,000行数据(行中每个字段的一个对象,因此可能总共在20到50个对象之间),但我们的客户已经在询问增加限制为1,000,000 - 所以我们已经在我们的调用代码中存储了数据字典,因此我们可以在那里验证它,我们必须在这些对象中存储它的副本。如果它们只是double的当前限制,那么它在20MB到50MB之间,或者在预计的未来需求上为200MB-500MB。
  3. 对于我们目前不需要做的事情,这是一个巨大的开销!


    1 警告:有些人可能不愿意在办公室里谷歌这样做!

1 个答案:

答案 0 :(得分:1)

这可能取决于项目的关键性和质量标准,但我的直觉是你通常不应该让#34;未定义的行为"进入你的系统,特别是如果"垃圾结果"生产。

你说你担心一个狂热的团队成员会给套件增加一个不一致的测试。您可能会假设团队成员在编写生产代码之前总会添加测试,从而遇到您的&#34; parapet&#34;测试,但如果他们不干扰怎么办?主要的安全措施是不是要防止他们首先<错误地使用API​​ (即正确处理边缘情况)?