单元测试和有序测试 - 最佳实践

时间:2011-07-08 09:29:35

标签: unit-testing model-view-controller

我有一个Web应用程序的复杂部分,我们现在开始对它进行单元测试,以确保一切正常,如果有任何更改,测试将在那里检查是否我们打破了什么。

我们的应用程序的这一部分是一种向导:您从步骤1转到步骤N.每个步骤都可以根据用户选择的内容以不同的方式进行分叉。每个步骤也可以只包含1个项目或项目集合,如下所示:

  • 第1步:是否有X型物品?如果有,有多少?
    • 对于声明的每件商品 - >表格输入项目数据
  • 第2步:是否有Y型物品?如果有,有多少?
    • 对于声明的每件商品 - >表单输入项目数据(可能包含对步骤1中声明的项目的引用)

等。这不是全部,有例外,但它只是想知道它是如何形成的。现在这个程序不仅仅是前瞻性的。用户必须能够跳回到以前的节点并应用更改,添加项目或从集合中删除项目等,软件必须记住他在跳回之前完成的最后一步是什么,所以当他完成后他可以继续。

出于单元测试的目的,我想我不能进行独立测试:如果你还没有完成前面的步骤,那么就没有连续步骤的数据。因此,我在考虑编写有序测试。

我还读到,最佳做法是“让测试彼此独立”,而我认为要做的就是反对这一点。

如果作为有序测试运行,我写的样本测试是绿色的,但如果作为独立测试运行,则只有第一个是绿色。

现在我想听听意见,如果有人有正确的方法来处理这种情况。

3 个答案:

答案 0 :(得分:2)

每个测试确实应该彼此独立。如果测试B依赖于之前执行的测试A,那么您的手上可能会进行非常严格的测试。在您的情况下,我更愿意通过预先配置上下文来SetUp测试B.

我的意思是,无论测试A在完成后离开系统的状态如何,使用它来设置测试B的上下文,例如。

public void TestB()
{
    // Arrange.
    SetupSystemLikeTestAHadJustRun();

   // Act.
   // Do your tests.

   // Assert.
}

通过在测试开始时拥有一个已知的,固定的上下文,你有更好的机会进行一系列测试。

或者,如果您听说过BDD(行为驱动开发),您可以使用BDF工具,如SpecFlow或NBehave(用于.NET)或Cucumber用于Ruby。使用BDD可以让您在测试中更具表现力。

答案 1 :(得分:1)

该做与不做 要做

名称测试及其预期结果和要测试的状态或输入的相关详细信息

不要

给出测试名称,除了琐碎的情况外,只说出被测试方法的名称

结构

结构测试分为三个不同的部分-排列,执行和声明。

单元测试往往具有非常规则的结构。引用此结构的一种常见方式是安排,执行,声明:每个测试都必须安排要测试的世界的状态,通过调用方法对被测类进行操作,并断言此后的世界处于预期状态。 / p>

range块用于设置特定于测试情况的​​外部世界的详细信息。这涉及到诸如创建将在测试中重用的局部变量之类的事情,有时还会使用特定的参数实例化被测对象。该步骤不应涉及对被测对象的任何调用(在动作块期间执行此操作)或对初始状态的验证(在断言期间(可能在另一个测试中进行))。请注意,所有或许多测试所需的常规设置应在测试的setUp方法中完成。如果您的测试不依赖于任何特定的外部状态,则可以跳过“排列”块。

act块是您实际对被测类进行调用以触发被测行为的地方。通常,此块是单个方法调用,但是如果您要测试的行为跨越多个方法,则将在此处分别调用它们。可以内联简单的参数作为方法调用的一部分,但是有时最好将更复杂的参数表达式提取到ranging块中,以免分散该块的意图。 act块还可以将方法的返回值分配给局部变量,以便以后可以断言。

assert块是对收集的返回值进行断言并验证与模拟对象的任何交互的地方。它还可以建立断言和验证所需的值。在非常简单的测试中,有时通过将对被测类的调用内联到assert语句中来组合act和assert块。

这些块应该彼此不同-测试在行为块中对被测类进行调用后,测试不应执行任何其他设置或存根,并且一旦验证,就不应进一步对被测类进行调用从断言块开始。

在浏览每个块的开始和结束位置时应该很清楚。通常,可以通过在每个块之间添加一条空行来完成此操作(尽管在简单的测试中,块仅需一行或两行是不必要的)。在特别复杂的测试中,尤其是在必须设置多个不同对象的测试中,您可能希望在块中使用空行以使其更具可读性。在这种情况下,区分块的一种方法是在每个块上标注//排列,//动作和//声明等注释。

强调这种结构的测试更加清晰,因为它们可以轻松浏览测试的不同部分,并且由于常规结构有助于确保所测试行为的细节不会被隐藏或省略,因此更有可能完成测试。

模拟框架以不同的方式与该结构交互。像Mockito这样的大多数现代框架都允许在安排块中配置存根以及定义局部变量,并在断言块中验证模拟并执行断言。不幸的是,像EasyMock这样的一些较早的框架要求在调用被测代码之前先指定模拟的预期行为-这需要在act块之前第四个“ expect”块,该块的工作方式与assert块类似。

答案 2 :(得分:0)

我会使用像黄瓜或硒这样的工具来测试你描述的图形内容。您可以使用像junit和nunit这样的单元测试框架来编写这些类型的测试,但这些测试并不真正支持运行有序测试。

相关问题