Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Extending Spock: Outputting the Given, When, Then

DZone's Guide to

Extending Spock: Outputting the Given, When, Then

Let's check out how to use Spock's extension framework to output testing scenarios into log files for quick, easy QA review!

· Java Zone ·
Free Resource

How do you break a Monolith into Microservices at Scale? This ebook shows strategies and techniques for building scalable and resilient microservices.

Spock is a Java testing framework created in 2008 by Peter Niederwieser, a software engineer with GradleWare, which facilitates, amongst other things, BDD. Leveraging this example, a story may be defined as:

Story: Returns go to stock

As a store owner
In order to keep track of stock
I want to add items back to stock when they're returned.

Scenario 1: Refunded items should be returned to stock
Given that a customer previously bought a black sweater from me
And I have three black sweaters in stock.
When he returns the black sweater for a refund
Then I should have four black sweaters in stock.

Scenario 2: Replaced items should be returned to stock
Given that a customer previously bought a blue garment from me
And I have two blue garments in stock
And three black garments in stock.
When he returns the blue garment for a replacement in black
Then I should have three blue garments in stock
And three black garments in stock.


Spock makes it possible to map tests very closely to scenario specifications using the same given, when, then format. In Spock, we could implement the first scenario as:

class SampleSpec extends Specification{
    def "Scenario 1: Refunded items should be returned to stock"() {
        given: "that a customer previously bought a black sweater from me"
        // ... code 
        and: "I have three black sweaters in stock."
        // ... code
        when: "he returns the black sweater for a refund"
        // ... code
        then: "I should have four black sweaters in stock."
        // ... code
    }
}


It would be nice to ensure accurate mapping of test scenario requirements to test scenario implementations. We could get somewhat down this path if we could output the syntax of the given, when, then from our test. Spock allows us to add this functionality through its extension framework.

So, let's say our BA is really curious and wants more confidence from the developer that they stuck to the same given, when, then format and their code is in-sync. They want to get this information easily. The developer could provide this information by first defining this annotation

import java.lang.annotation.*
import org.spockframework.runtime.extension.ExtensionAnnotation
 
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@ExtensionAnnotation(ReportExtension)
@interface LogScenarioDescription {}


Followed by this implementation:

import org.apache.log4j.Logger
import org.spockframework.runtime.AbstractRunListener
import org.spockframework.runtime.extension.AbstractAnnotationDrivenExtension
import org.spockframework.runtime.model.FeatureInfo
import org.spockframework.runtime.model.SpecInfo
 
 
class LogScenarioDescriptionExtension extends AbstractAnnotationDrivenExtension<logscenariodescription>; {
    final static Logger logger = Logger.getLogger("scenarioLog." + ReportExtension.class);
 
    @Override
    void visitSpecAnnotation(Report annotation, SpecInfo spec) {
        spec.addListener(new AbstractRunListener() {
            @Override
            void afterFeature(FeatureInfo feature) {
                if (System.getEnv("logScenarios")) {
                    logger.info("***SCENARIO TEST:*** " + feature.name)
                    for (block in feature.blocks) {
                        logger.info(block.kind);
                        for (text in block.texts) {
                            logger.info(text)
                        }
                    }
                }
            }
        })
    }
}
</logscenariodescription>


This will then be applied to the test:

@LogScenarioDescriptionExtension
class SampleSpec extends Specification{
  //...


When the test is executed, it gives the following output:

***SCENARIO TEST:*** Scenario 1: Refunded items should be returned to stock
GIVEN
that a customer previously bought a black sweater from me
AND
I have three black sweaters in stock.
WHEN
he returns the black sweater for a refund
THEN
I should have four black sweaters in stock.


Output to a specific logfile for scenario logging by using the following log4j:

log4j.rootLogger=INFO, stdout

log4j.logger.scenarioLog.extension.custom=INFO, scenarioLog

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%m%n

log4j.appender.scenarioLog=org.apache.log4j.FileAppender
log4j.appender.scenarioLog.File=logs/scenario.log
log4j.appender.scenarioLog.layout=org.apache.log4j.PatternLayout
log4j.appender.scenarioLog.layout.ConversionPattern=%m%n


And now you have a logfile that your BA/QA can read! This helps foster an Agile culture of collaboration and ATDD where it possible to check that test scenarios were implemented with the agreed upon criteria.

How do you break a Monolith into Microservices at Scale? This ebook shows strategies and techniques for building scalable and resilient microservices.

Topics:
java ,spock ,java testing ,given when then ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}