如何加快JUnit参数化测试的创建

在编写单元测试时,通常在测试方法本身中初始化方法输入参数和预期结果。在某些情况下,使用一小组输入就足够了; 但是,在某些情况下,我们需要使用大量值来验证代码中的所有功能。参数化测试是定义和运行多个测试用例的好方法,其中它们之间的唯一区别是数据。他们可以验证各种值的代码行为,包括边界情况。参数化测试可以增加代码覆盖率并确保代码按预期工作。

Java有许多优秀的参数化框架。在本文中,我们将介绍JUnit测试常用的三种不同框架,并对它们之间的比较以及每种框架的测试结构示例进行比较。最后,我们将探索如何简化和加快参数化测试的创建。

参数化JUnit测试框架

让我们比较3个最常见的框架:JUnit 4,JunitParams和JUnit 5.每个JUnit参数化框架都有自己的优点和缺点。

JUnit 4

优点:

  • 这是JUnit 4中内置的参数化框架,因此不需要额外的外部依赖项。
  • 它支持旧版本的Java(JDK 7及更早版本)。

缺点:

  • 测试类使用字段和构造函数来定义参数,这使得测试更加冗长。
  • 对于每个被测试的方法,它需要一个单独的测试类。

JUnitParams

优点:

  • 通过允许将参数直接传递给测试方法来简化参数语法。
  • 允许每个测试类使用多种测试方法(每种方法都有自己的数据)。
  • 支持CSV数据源以及基于注释的值(无需方法)。

缺点:

  • 需要使用JunitParams依赖项配置项目。
  • 运行和调试测试时,必须运行类中的所有测试 - 不可能在测试类中运行单个测试方法。

JUnit 5

优点:

  • 此参数化框架内置于JUnit 5中,并改进了JUnit 4中包含的内容。
  • 有简化的参数语法,如JunitParams。
  • 支持多种数据集源类型,包括CSV和注释(无需方法)。
  • 即使不需要额外的依赖项,也需要多个.jar。

缺点:

  • 需要Java 8及更高版本的构建系统(Gradle 4.6或Maven Surefire 2.21)。
  • 您的IDE可能尚不支持(截至本文撰写时,只有Eclipse和IntelliJ支持JUnit 5)。

例如,假设我们有一个处理银行贷款请求的方法。我们可能会编写一个单元测试,指定贷款请求金额,预付金额和其他值。然后,我们将创建验证响应的断言 - 贷款可能被批准或拒绝,并且响应可以指定贷款的条款。

例如:

首先,让我们看一下上述方法的常规测试:

在这个例子中,我们通过申请1000美元贷款来测试我们的方法,首付200美元并且表明请求者有250美元的可用资金。然后,测试验证贷款已获批准,并且未在响应中提供消息。

为了确保我们的requestLoan()方法得到彻底测试,我们需要测试各种预付款,请求的贷款金额和可用资金。例如,让我们测试100万美元的贷款申请,零首付,这应该被拒绝。我们可以简单地用不同的值复制现有的测试,但由于测试逻辑是相同的,因此更有效地参数化测试。

我们将参数化所请求的贷款金额,首付款和可用资金,以及预期结果:贷款是否获得批准,以及验证后返回的消息。每组请求数据及其预期结果将成为其自己的测试用例。

使用JUnit 4参数化的示例参数化测试

让我们从Junit 4参数化示例开始。要创建参数化测试,我们首先需要为测试定义变量。我们还需要包含一个构造函数来初始化它们:

在这里,我们看到测试使用@RunWith注释指定测试将使用Junit4参数化运行器运行。此运行器知道要查找一个方法,该方法将为测试提供值集(使用@Parameters注释),正确初始化测试,并运行多行测试。

请注意,每个参数都定义为测试类中的一个字段,构造函数初始化这些值(如果您不想创建构造函数,也可以使用@Parameter注释将值注入字段)。对于值集中的每一行,参数化运行器将实例化测试类并在类中运行每个测试。

让我们添加一个为Parameterized runner 提供参数的方法:

值集通过data()方法构建为Object数组列表,该方法使用@Parameters进行注释。请注意,@Parameters使用占位符设置测试的名称,在测试运行时将替换它们。这样可以更轻松地查看测试结果中的值,我们稍后会看到。目前,只有一行数据,用于测试贷款应该获得批准的情况。我们可以添加更多行来增加测试方法的覆盖范围。

在这里,我们有一个测试案例,其中贷款将被批准,以及两个案例,由于不同的原因,它不应被批准。我们可能想要添加使用零值或负值的行,以及测试边界条件。

我们现在准备创建测试方法:

在这里,我们在调用requestLoan()方法并验证结果时引用字段。

JUnitParams示例

JunitParams库通过允许将参数直接传递给测试方法来简化参数化测试语法。参数值由单独的方法提供,其名称在@Parameters注释中引用。

除了在代码中提供值之外,JunitParams还有一个额外的好处,它支持使用CSV文件提供值。这允许在不更新代码的情况下将测试与要更新的数据和数据值分离。

JUnit 5示例

JUnit 5解决了JUnit 4的一些局限性和缺点。与JunitParams一样,Junit 5也简化了参数化测试的语法。语法中最重要的变化是:

  • 测试方法使用@ParameterizedTest而不是@Test进行注释
  • 测试方法直接接受参数,而不是使用字段和构造函数
  • @RunWith注解不再需要

在Junit 5中定义相同的示例将如下所示:

有效地创建参数化测试

可以想象,编写上面的参数化测试可能有点工作。对于每个参数化测试框架,都需要正确编写一些样板代码。很难记住正确的结构,写出来需要时间。为了使这更容易,您可以使用Parasoft Jtest自动生成参数化测试,如上所述。要执行此操作,只需选择要为其生成测试的方法(在Eclipse或IntelliJ中),然后单击Parasoft Jtest的单元测试助手视图中的参数化操作:

使用默认值和断言生成测试。然后,您可以使用实际输入值和断言配置测试,并向data()方法添加更多数据行。

运行参数化测试

Parasoft Jtest可以直接在Eclipse和IntelliJ中运行参数化测试。

Eclipse中的JUnit视图。

请注意,每个测试的名称(如图所示)包括数据集的输入值和预期结果值。这可以使测试失败时更容易调试,因为每种情况都显示输入参数和预期输出。

您还可以使用Parasoft Jtest的“全部运行”操作:

Parasoft Jtest中的Flow Tree视图。

它分析测试流程并提供有关先前测试运行的详细信息。这使您可以查看测试中发生的情况,而无需使用断点或调试语句重新运行测试。例如,您可以在Variables视图中看到参数化值:

Parasoft Jtest中的变量视图。

结论

我们审查的三个框架是很好的选择并且运作良好。如果使用JUnit 4,我更喜欢JunitParams而不是内置的JUnit 4参数化框架,因为测试类的设计更简洁,并且能够在同一个类中定义多个测试方法。但是,如果使用JUnit 5,我建议使用内置的JUnit 5框架,因为它解决了JUnit 4中的缺点,并且不需要额外的库。我还喜欢使用Parasoft Jtest的单元测试功能来更有效地创建,执行和调试参数化测试。

猜你喜欢

转载自blog.csdn.net/Tybyqi/article/details/82888639