Outputting the given, when, then, Extending Spock
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 } }
What would be nice would be to ensure accurate mapping of test scenario requirements to test scenario implementation. We could get someway 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. 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; { 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) } } } } }) } }
This will then be applied to the test
@LogScenarioDescription 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 implemented with those that were agreed.
Reference: | Outputting the given, when, then, Extending Spock from our JCG partner Alex Staveley at the Dublin’s Tech Blog blog. |