您的位置:软件测试 > 开源软件测试 > 开源单元测试工具 > junit
使用 JUnit 5 进行单元测试
作者:ibm 发布时间:[ 2017/3/24 15:27:42 ] 推荐标签:单元测试 Junit 5 单元测试工具

  动态测试
  目前所介绍的 JUnit 5 测试方法的创建都是静态的,在编译时刻已经存在。JUnit 5 新增了对动态测试的支持,可以在运行时动态创建测试并执行。通过动态测试,可以满足一些静态测试无法解的需求,也可以完成一些重复性很高的测试。比如,有些测试用例可能依赖运行时的变量,有时候会需要生成上百个不同的测试用例。这些场景都是动态测试可以发挥其长处的地方。动态测试是通过新的@TestFactory 注解来实现的。测试类中的方法可以添加@TestFactory 注解的方法来声明其是创建动态测试的工厂方法。这样的工厂方法需要返回 org.junit.jupiter.api.DynamicTest 类的集合,可以是 Stream、Collection、Iterable 或 Iterator 对象。每个表示动态测试的 DynamicTest 对象由显示名称和对应的 Executable 接口的实现对象来组成。清单 13 中展示了@TestFactory 的示例。
  清单 13. 动态测试
  @TestFactory
  public Collection<DynamicTest> simpleDynamicTest() {
  return Collections.singleton(dynamicTest
  ("simple dynamic test", () -> assertTrue(2 > 1)));
  }
  DynamicTest 提供了一个静态方法 stream 来根据输入生成动态测试,如清单 14 所示。
  清单 14. 通过 stream 方法来生成动态测试
  @TestFactory
  public Stream<DynamicTest> streamDynamicTest() {
  return stream(
  Stream.of("Hello", "World").iterator(),
  (word) -> String.format("Test - %s", word),
  (word) -> assertTrue(word.length() > 4)
  );
  }
  执行测试用例
  JUnit 5 提供了三种不同的方式来执行测试用例,分别是通过 Gradle 插件、Maven 插件和命令行来运行。
  Gradle
  JUnit 5 提供了 Gradle 插件,在 Gradle 项目中运行单元测试,如清单 15 所示。
  清单 15. 使用 JUnit 5 的 Gradle 插件
  buildscript {
  repositories {
  mavenCentral()
  }
  dependencies {
  classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-M2'
  }
  }
  apply plugin: 'org.junit.platform.gradle.plugin'
  在启用了 Gradle 插件之后,可以通过 junitPlatformTest 任务来运行单元测试。可以在 Gradle 脚本中对插件进行定制,如通过 reportsDir 设置测试结果报告的生成路径,通过 tags 来设置包含或排除的标签名称,如清单 16 所示。
  清单 16. 配置 JUnit 5 的 Gradle 插件
  junitPlatform {
  platformVersion 1.0
  reportsDir "build/test-results/junit-platform"
  tags {
  include 'fast', 'smoke'
  }
  }
  Maven
  在 Maven 项目中可以通过 Surefire 插件来运行 JUnit 5 测试,只需要在 POM 文件中进行配置即可。如清单 17 所示。
  清单 17. 在 Maven 项目中使用 JUnit 5
  <build>
  <plugins>
  <plugin>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.19</version>
  <dependencies>
  <dependency>
  <groupId>org.junit.platform</groupId>
  <artifactId>junit-platform-surefire-provider</artifactId>
  <version>1.0.0-M2</version>
  </dependency>
  </dependencies>
  </plugin>
  </plugins>
  </build>
  命令行
  除了 Gradle 和 Maven 之外,还可以通过命令行来运行 JUnit 5 测试。只需要直接运行 Java 类 org.junit.platform.console.ConsoleLauncher 即可。ConsoleLauncher 提供了不同的命令行参数来配置测试运行的行为,如-n 来指定包含的 Java 类名满足的模式,-t 来包含标签,-T 来排除标签。
  扩展机制
  JUnit 5 提供了标准的扩展机制来允许开发人员对 JUnit 5 的功能进行增强。JUnit 5 提供了很多的标准扩展接口,第三方可以直接实现这些接口来提供自定义的行为。通过@ExtendWith 注解可以声明在测试方法和类的执行中启用相应的扩展。
  扩展的启用是继承的,这既包括测试类本身的层次结构,也包括测试类中的测试方法。也是说,测试类会继承其父类中的扩展,测试方法会继承其所在类中的扩展。除此之外,在一个测试上下文中,每一个扩展只能出现一次。
  创建扩展
  JUnit 5 中的扩展非常容易创建,只是实现了特定接口的 Java 类。JUnit 5 的扩展都需要实现 org.junit.jupiter.api.extension.Extension 接口,不过该接口只是一个标记接口,并没有任何需要实现的具体方法。真正起作用的是 Extension 的子接口,作为 JUnit 5 提供的扩展点。
  测试执行条件
  ContainerExecutionCondition 和 TestExecutionCondition 接口用来配置是否启用测试类或测试方法。前面提到的@Disabled 注解也是通过这样的机制来实现的。ContainerExecutionCondition 接口对应的是测试类,而 TestExecutionCondition 接口对应的是测试方法。
  ContainerExecutionCondition 接口的 evaluate 方法接受 ContainerExtensionContext 接口作为参数,并返回 ConditionEvaluationResult 类的对象作为结果。通过 ContainerExtensionContext 接口可以获取到当前测试类的上下文信息,而 ConditionEvaluationResult 类则表示该测试类是否被启用。
  TestExecutionCondition 接口也是包含一个 evaluate 方法,只不过参数类型是 TestExtensionContext,其返回结果也是 ConditionEvaluationResult 类的对象。
  通过扩展的方式禁用的测试类和方法,可以通过 JVM 参数 junit.conditions.deactivate 来重新启用,只需要把相应的条件类禁用即可。
  清单 18 中扩展 DisableAPITests 实现了 ContainerExecutionCondition 和 TestExecutionCondition 接口,当测试类或方法中包含标签 api 时,通过 ConditionEvaluationResult.disabled()表示对其禁用。
  清单 18. 测试执行条件扩展示例
  public class DisableAPITests implements ContainerExecutionCondition,
  TestExecutionCondition {
  @Override
  public ConditionEvaluationResult evaluate
  (final ContainerExtensionContext context) {
  return checkTags(context.getTags());
  }
  @Override
  public ConditionEvaluationResult evaluate
  (final TestExtensionContext context) {
  return checkTags(context.getTags());
  }
  private ConditionEvaluationResult checkTags
  (final Set<String> tags) {
  if (tags.contains("api")) {
  return ConditionEvaluationResult.disabled("No API tests!");
  }
  return ConditionEvaluationResult.enabled("");
  }
  }
  清单 19 中的测试类的 simpleAPITest 方法使用了标签 api,在执行时会被禁用。
  清单 19. 使用 DisableAPITests 的测试用例
  @ExtendWith(DisableAPITests.class)
  public class APITests {
  @Test
  @Tag("api")
  public void simpleAPITest() {
  System.out.println("simple API test");
  }
  }
  后处理测试实例
  通过 TestInstancePostProcessor 可以对测试实例添加后处理的逻辑,从而进一步对实例进行定制,比如可以通过依赖注入的方式来设置其中的属性,或是添加额外的初始化逻辑等。
  在清单 20 中,扩展 InjectAPIEnv 实现了 TestInstancePostProcessor 接口,在 postProcessTestInstance 方法中通过 Commons Lang 中的 MethodUtils.invokeMethod 来调用当前测试实例中的 setEnv 方法,并设置为 DEV。
  清单 20. 后处理测试实例的示例
  public class InjectAPIEnv implements TestInstancePostProcessor {
  @Override
  public void postProcessTestInstance
  (final Object testInstance,
  final ExtensionContext context) throws Exception {
  MethodUtils.invokeMethod(testInstance, "setEnv", "DEV");
  }
  }
  清单 21 中给出了使用该扩展的示例。
  清单 21. 使用后处理测试实例的示例
  @ExtendWith(InjectAPIEnv.class)
  public class APITests {
  private String env;
  public void setEnv(final String env) {
  this.env = env;
  }
  @Test
  public void showInjected() {
  assertEquals("DEV", this.env);
  }
  }
  参数解析
  在之前介绍 JUnit 5 的参数解析时,提到了 JUnit 5 可以自动解析 TestInfo 和 TestReporter 类型的参数。除了这两种类型的参数之外,也可以通过扩展 ParameterResolver 接口来提供自定义的参数解析功能。ParameterResolver 接口中有两个方法,分别是 supports 和 resolve。两个方法的参数是一样的,分别是 ParameterContext 和 ExtensionContext 接口的对象。通过 ParameterContext 可以获取到需要解析的参数的信息,而 ExtensionContext 接口可以获取到当前测试类或方法的上下文信息。
上一页1234下一页
软件测试工具 | 联系我们 | 投诉建议 | 诚聘英才 | 申请使用列表 | 网站地图
沪ICP备07036474 2003-2017 版权所有 上海泽众软件科技有限公司 Shanghai ZeZhong Software Co.,Ltd