How to extract BDD metadata from Spock specification classes

Suppose we have a Spock specification class, as shown below.

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()
    }
}

How can I extract the metadata of the BDD, such as some scenario, given, when, then? Process the source file directly, but I wonder if reflection can be used to achieve this.

BTW, the motivation for obtaining this information is to facilitate communication between the product owner and the developer, so that the product owner can know what actions have been implemented and verified without looking at the source code.

Many thanks.

+4
source share
1 answer

There are some problems with this in the cold harsh daylight.

  • , , , ( , ? helper methods?)
  • , .

, , @PeterNiederwieser .

, , , AST Groovy String...


, , .

, 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'

, ...

+5

Source: https://habr.com/ru/post/1527752/


All Articles