【问题标题】:How to extract BDD meta-statements from Spock specification classes如何从 Spock 规范类中提取 BDD 元语句
【发布时间】:2014-02-19 17:06:24
【问题描述】:

假设我们有一个如下所示的 Spock 规范类。

class SomeFeature extends Specification {
    def "some scenario"() {
        given: "some resource"
        def resource = someResource()

        when: "some action is taken"
        someAction()

        then: "some condition must be met"
        true == someCondition()
    }
}

如何提取 BDD 元语句,如 some scenariogivenwhenthen?处理源文件很简单,但我想知道是否可以使用反射来实现这一点。

顺便说一句,获取该信息的动机是促进产品所有者和开发人员之间的沟通,以便产品所有者无需查看源代码即可知道已实现和验证了哪些行为。

非常感谢。

【问题讨论】:

  • stackoverflow.com/questions/13690778/…。块描述可用于扩展。 Spock 1.0 将附带支持 BDD 样式的报告。
  • @PeterNiederwieser Lol 这比我的砍树要好得多:-D
  • @PeterNiederwieser 非常感谢。我刚刚玩了报告扩展。它绝对展示了 Spock 做我正在寻找的事情的能力。我很高兴看到这个功能成为稳定版本的一部分。顺便说一句,在我们选择一个作为我们公司的标准之前,我们正在评估一些 BDD 框架,包括 Spock 和 Cucumber。这个报告功能肯定会让 Spock 在与 Cucumber 竞争中处于更有利的地位。

标签: java groovy bdd spock


【解决方案1】:

在寒冷的强光下,这有一些问题。

  1. 它可能很脆弱,需要整理以处理不同的情况和格式(展开描述?辅助方法?参数化描述?)
  2. 即使从未执行过测试,它也会盲目地转储所有内容。

我认为上面@PeterNiederwieser 评论中的解决方案会更好、更稳定。

我将把它留在这里,因为它是一个很好的例子,说明如何将一些 Groovy 代码作为字符串生成 AST...


我认为反射不会有帮助,因为它不会让您了解方法的内容。

您可以通过从源代码生成 AST,然后遍历它寻找感兴趣的节点来实现。

所以给出这样的字符串中的代码:

def code = '''import spock.*

class SomeFeature extends Specification {
    def "some scenario"() {
        given: "some resource"
        def resource = someResource()

        when: "some action is taken"
        someAction()

        then: "some condition must be met"
        true == someCondition()
    }
    def "another"() {
       given: 'a value 1'
          def value = 1
       then: '1 == 1'
          value == 1
    }
}'''

您可以生成 AST:

import org.codehaus.groovy.antlr.*
import org.codehaus.groovy.antlr.parser.*

def ast = new GroovyRecognizer(
              new GroovyLexer(
                  new StringReader( code ) ).plumb() ).with { p ->
  p.compilationUnit()
  p.AST
}

然后你可以做这样的事情(这可能不是最干净的方法,我时间有限);-)

while( ast ) {
    if( ast.type == GroovyTokenTypes.CLASS_DEF ) {
        def child = ast.firstChild.nextSibling
        println "Specification '${child.text}'"
        while( child && child.type != GroovyTokenTypes.OBJBLOCK ) {
            child = child.nextSibling
        }
        if( child ) {
            child = child.firstChild
            while( child ) {
                if( child.type == GroovyTokenTypes.METHOD_DEF ) {
                    def method = child.firstChild
                    println "    Scenario '${method.nextSibling?.nextSibling?.text}'"
                    while( method ) {
                        if( method.type == GroovyTokenTypes.SLIST ) {
                            def statements = method.firstChild
                            while( statements ) {
                                if( statements.type == GroovyTokenTypes.LABELED_STAT ) {
                                    def label = statements.firstChild
                                    println "        ${label.text.toUpperCase()} '${label.nextSibling?.firstChild?.text}'"
                                }
                                statements = statements.nextSibling
                            }
                        }
                        method = method.nextSibling
                    }
                }
                child = child.nextSibling
            }
        }
    }
    ast = ast.nextSibling
}

这给了我输出:

Specification 'SomeFeature'
    Scenario 'some scenario'
        GIVEN 'some resource'
        WHEN 'some action is taken'
        THEN 'some condition must be met'
    Scenario 'another'
        GIVEN 'a value 1'
        THEN '1 == 1'

希望对你有帮助...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-20
    • 2010-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多