testing - 在Specification.cleanup()中查找测试的结果/状态

标签 testing spock

这似乎是一件合理的事情……例如当测试失败时记录一些内容,如果没有失败则不记录一些内容。

我找到了this比如说,从2013年开始……当时没有既简单又有效的答案。那现在呢?

我希望可以在 org.spockframework.runtime.SpecificationContext 中找到合适的属性/方法...或者可能在 org.spockframework.runtime.model.SpecInfo 中找到。 ..但我什么也看不到。

稍后

要回答我可能想做的事情的问题:实际上我的规范是“劫持”System.out(使用PrintStream ),这样我就可以捕获输出到System.out,然后对其进行分析。请注意,我知道 Spock 纯粹主义者可能不赞成对终端输出感兴趣的测试,但我不是这样的纯粹主义者,特别是在谈论单元测试以外的测试时。

以某种方式获得此输出意味着它不会输出到任何地方,因此没有理由系统地记录它并弄乱日志文件......但如果测试失败,我想这样做。同样可能适用于 System.err...

最佳答案

首先,记录失败的测试是您的测试框架(JUnit、Spock)的工作。因此,测试本身的状态不容易从测试本身中获得,这并不奇怪。不管怎样,如果你想要 Spock 中更奇特的东西,accepted answer还有Peter's answer在另一个线程中仍然有效。没有更简单的方法可以通过 cleanup() 方法确定测试是否失败。

无论如何,它并不像看起来那么复杂,因为你只需要设置一次,然后它就可以工作了。由于您没有提到您到底想在 cleanup() 中登录什么,我将进行一些推测。出于演示目的,我只是记录从规范上下文中检索的功能方法名称,以及从注册的运行监听器中检索的已发生错误的类(以免打印整个花哨的 Spock 错误消息两次)我将在这里介绍全局扩展。

全局 Spock 扩展:

该扩展注册一个运行监听器,每当发生测试错误时该监听器都会记录错误信息。在每个功能或迭代开始时(对于具有 where: block 的功能),最后记录的错误将被清除,以免渗透到下一个功能/迭代中。

package de.scrum_master.testing.extension

import org.spockframework.runtime.AbstractRunListener
import org.spockframework.runtime.extension.AbstractGlobalExtension
import org.spockframework.runtime.model.ErrorInfo
import org.spockframework.runtime.model.IterationInfo
import org.spockframework.runtime.model.SpecInfo

class TestResultExtension extends AbstractGlobalExtension {
  @Override
  void visitSpec(SpecInfo spec) {
    spec.addListener(new ErrorListener())
  }

  static class ErrorListener extends AbstractRunListener {
    ErrorInfo errorInfo

    @Override
    void beforeIteration(IterationInfo iteration) {
      errorInfo = null
    }

    @Override
    void error(ErrorInfo error) {
      errorInfo = error
    }
  }
}

如何注册 Spock 扩展:

您还需要将文件 META-INF/services/org.spockframework.runtime.extension.IGlobalExtension 添加到您的测试资源中才能注册扩展。该文件仅包含以下内容:

de.scrum_master.testing.extension.TestResultExtension

顺便说一句,这不是 Spock 或 Groovy 的东西,而是一个名为 service providers 的标准 Java SE 功能。 .

使用扩展程序的示例测试:

这个测试非常愚蠢,但显示了它如何适用于普通方法以及带有 where: block 的方法,无论是否带有 @Unroll

package de.scrum_master.testing.extension

import spock.lang.Specification
import spock.lang.Unroll

class TestFailureReportingTest extends Specification {
  def "failing normal feature"() {
    expect:
    0 == 1
  }

  def "passing normal feature"() {
    expect:
    0 == 0
  }

  def "parametrised feature"() {
    expect:
    a == b

    where:
    a << [2, 4, 6]
    b << [3, 5, 6]
  }

  @Unroll
  def "unrolled feature with #a/#b"() {
    expect:
    a == b

    where:
    a << [6, 8, 0]
    b << [7, 9, 0]
  }

  def cleanup() {
    specificationContext.currentSpec.listeners
      .findAll { it instanceof TestResultExtension.ErrorListener }
      .each {
        def errorInfo = (it as TestResultExtension.ErrorListener).errorInfo
        if (errorInfo)
          println "Test failure in feature '${specificationContext.currentIteration.name}', " +
            "exception class ${errorInfo.exception.class.simpleName}"
        else
          println "Test passed in feature '${specificationContext.currentIteration.name}'"
      }
  }
}

控制台日志(忽略实际错误)将是:

Test failure in feature 'failing normal feature', exception class ConditionNotSatisfiedError

Test passed in feature 'passing normal feature'

Test failure in feature 'parametrised feature', exception class ConditionNotSatisfiedError
Test failure in feature 'parametrised feature', exception class ConditionNotSatisfiedError
Test passed in feature 'parametrised feature'

Test failure in feature 'unrolled feature with 6/7', exception class ConditionNotSatisfiedError
Test failure in feature 'unrolled feature with 8/9', exception class ConditionNotSatisfiedError
Test passed in feature 'unrolled feature with 0/0'

P.S.:错误信息在功能方法内的 cleanup: block 中可用,因为扩展仅在包括该 block 的整个功能/迭代之后启动已运行完毕。因此,您确实必须使用 cleanup() 方法,但无论如何您都需要这样做,并且它可以避免代码重复。

P.P.S.:当然,您也可以只在方法拦截器中进行通用日志记录,并跳过整个 cleanup() 方法。但是,您不再可以使日志输出特定于测试,它将适用于您的所有测试,而不仅仅是您选择的测试 - 当然,除非您硬编码包或规范名称过滤器直接进入拦截器或确保拦截器在 Spock 启动时读取相应的配置文件。

关于testing - 在Specification.cleanup()中查找测试的结果/状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50666160/

相关文章:

spring - 将规则注入(inject) spock 规范

java - 针对更多类型的数据库运行 JUnit 测试

testing - 学习 GEB 和 Spock

grails - 从Intellij启动Geb测试

java - 每 'when' 步执行 Action Spock

使用放心的多个 GET 请求进行 Java 休息测试

angular - 测试组件元数据

testing - 在负载测试中测量SSL协商时间

javascript - 如何对 TweenMax 进行单元测试?潜在的模拟?

java - 如何测试持久层?