我对单元测试有疑问。我将用一个例子概述它。
假设我正在编写一个具有各种可接受命令的命令行应用程序,并且每个命令都有其可接受的参数。例如:myapp create -DprojectName = newProject -DprojectVersion = 1.0。
如果我有一个名为Command的类,它有一个validateArguments方法,它接收一个有效参数名列表并将它与用户指定的参数列表进行比较,你将如何进行单元测试呢?
我看到的可能性是:
您编写了两个单元测试 - 一个确保在传入有效参数时不会引发错误,另一个确保在传递无效参数时抛出错误。
您编写了一个单元测试,确保不会拒绝所有可接受的参数。我最终会对每个可接受的论点进行单元测试:
@Test public void validateArgments_ProjectNameArgPassed_NoExcepton thrown {...}
@Test public void validateArguments_ProjectVersionArgPassed_NoException抛出{...}
等等。
对我来说,第一种方法是有道理的。但它并不能确保每个应该被接受的论点都是。
答案 0 :(得分:5)
很难在不知道底层代码的逻辑的情况下建议(单元测试是白盒测试而不是黑盒子的原因)但我对该代码的处理方法是一系列单元测试,其中包含测试。 :
我发现单元测试的真正好处不在于测试成功场景,因为一些简单的集成测试也可以提供这样的好处。我发现真正的好处是测试了许多错误的场景,因为通常很少运行的代码(即错误处理)包含可能在未被注意的测试级别中滑过的错误。
答案 1 :(得分:2)
这取决于您使用的测试框架和语言。其中大多数(至少在C#中)允许您编写所谓的数据驱动的测试。这允许您使用要测试的参数提供测试方法,同时指定预期结果。
例如,Gallio这样的测试看起来像这样:
[Row("prj1", "1.0", true)]
[Row("blah", "Hippopotamus", false)]
[Row(null, "1.0", false, ExpectedException = typeof(NullReferenceException))]
public void TestArguments(string arg1, string arg2, bool expectedResult)
{
var result = myApp.ValidateArguments(args);
Assert.AreEqual(expectedResult, result);
}
这样,您可以轻松测试需要测试的所有参数组合,并且不需要太多代码。
设计不可能测试所有无效的参数,对于那些无效的参数,这通常(大部分)也是如此 - 它们在理论上可能是有限的,但实际上有太多可能的组合。在这种情况下,您所能做的就是测试人们可以想到的可能,重要和有意义的组合 从最终用户的角度/业务方面为此提供了很多帮助 - 他们经常会提出远远超出开发人员幻想的用例......
HTH。
托马斯
答案 2 :(得分:1)
同意dlanod,UNIT测试的范围应限于测试系统中最小的可编译组件。您的测试方法更倾向于灰盒测试,而不是说这不是正确的方法。同样很难确定应该使用什么方法取决于代码/类的大小和复杂性。
UNIT测试的另一个主要目标是确定代码覆盖水平,而不是功能覆盖。实际上,只有不到50%的代码服务90%的用例场景。如果您的应用程序很小,请使用灰盒方法,您可以在其中对UNIT和功能测试进行网格划分,否则最好有明确的分离。希望这可以帮助。
答案 3 :(得分:1)
我倾向于将其分解为代码的重要性。
如果它的代码涉及金钱,或其他一些代码失败是不可接受的功能,那么我会尝试测试每个可能的代码路径和结果。
从那以后的步骤将是广泛使用的代码,易于重构或其他功能,可能是脆弱的代码,然后我测试我认为是常见的用例。如果我后来发现由于我错过的用例而导致某些内容被破坏,我将为该案例添加一个测试。
底部是影响较小的代码 - 格式化/显示代码;直接的价值比较等,其中维持这些测试的成本超过了100%正确代码的好处。