Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for spock2 #784

Merged
merged 3 commits into from
Dec 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ subprojects {
testngVersion = '7.4.0'
assertjVersion = '3.20.2'
slf4jVersion = '1.7.32'
bytebuddyVersion = '1.11.13'
paranamerVersion = '2.8'
jansiVersion = '1.18'
gsonVersion = '2.8.8'
Expand All @@ -74,7 +73,7 @@ subprojects {
jacocoVersion = '0.8.5'
quickcheckVersion = '0.6'
hsqldbVersion = '2.3.2'
byteBuddyVersion = '1.10.2'
byteBuddyVersion = '1.12.3'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch :D

androidGradleVersion = '3.1.0'
androidCompileSdkVersion = 27
androidBuildToolsVersion = '27.0.2'
Expand Down
2 changes: 1 addition & 1 deletion jgiven-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dependencies {
api "com.google.guava:guava:$guavaVersion"
api "com.google.code.gson:gson:$gsonVersion"
implementation "com.thoughtworks.paranamer:paranamer:$paranamerVersion"
implementation "net.bytebuddy:byte-buddy:$bytebuddyVersion"
implementation "net.bytebuddy:byte-buddy:$byteBuddyVersion"
implementation "org.fusesource.jansi:jansi:$jansiVersion"

testImplementation 'com.github.stefanbirkner:system-rules:1.19.0'
Expand Down
1 change: 0 additions & 1 deletion jgiven-junit/.gitignore

This file was deleted.

1 change: 0 additions & 1 deletion jgiven-spock/.gitignore

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import org.junit.Rule
import spock.lang.Shared
import spock.lang.Specification

/**
* ScenarioSpec to use JGiven with Spock Framework
*
* @since 0.17.0
*/
class ScenarioSpec<GIVEN, WHEN, THEN> extends Specification {

@ClassRule @Shared JGivenClassRule writerRule = new JGivenClassRule()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class MyShinyJGivenShould extends ScenarioSpec<Given, When, Then> {
when().some_action()
then().some_outcome()

assert getScenario().getScenarioModel().getScenarioCases().get(0).getStep(0).words.join(" ") == "Given some state param"
assert scenario.scenarioModel.scenarioCases.first().getStep(0).words.join(" ") == "Given some state param"
}

@ExtendedDescription("more details")
Expand All @@ -36,7 +36,7 @@ class MyShinyJGivenShould extends ScenarioSpec<Given, When, Then> {
when().some_action()
then().some_outcome()

assert getScenario().getScenarioModel().getExtendedDescription() == "more details"
assert getScenario().getScenarioModel().extendedDescription == "more details"
}

@Unroll
Expand All @@ -46,7 +46,7 @@ class MyShinyJGivenShould extends ScenarioSpec<Given, When, Then> {
when().some_action()
then().some_outcome()

assert getScenario().getScenarioModel().getDescription() == "be able to use tables #param"
assert getScenario().getScenarioModel().description == "be able to use tables #param"

where:
param | _
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ class Given extends Stage<Given> {
def some_state_$(String param) {
self()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ class Then extends Stage<Then> {
assert true
self()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ class When extends Stage<When> {
When some_action() {
self()
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for polishing :)

27 changes: 27 additions & 0 deletions jgiven-spock2/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
plugins {
id 'java-library'
}

apply plugin: 'groovy'

description = "Module for writing JGiven tests with Spock 2"

ext {
spock2_version = '2.0-groovy-3.0'
groovy_version = '3.0.9'
}

dependencies {
api project(':jgiven-junit')

implementation "org.codehaus.groovy:groovy:$groovy_version"
implementation "org.spockframework:spock-core:$spock2_version"
implementation "org.spockframework:spock-junit4:$spock2_version"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: wouldn't it make sense to try to align the spock2 package with JUnit 5 directly? If I recall correctly Spock2 is JUnit5 based and upgrading the published jgiven package later should be significantly harder.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spock2 uses JUnit Platform used in JUnit5, but it does not use JUnit5. Therefore can not use the Junit5 Extensions.

At the end, it is an implementation detail for the user of the library. The user will not see that internally we are using JUnit4 Rules, but we can migrate to native Spock at some point in the future.

Using Spock2 allows users of the library to migrate to JDK17


testImplementation project(':jgiven-html5-report')
}

test {
useJUnitPlatform()
finalizedBy(jgivenHtml5Report)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.tngtech.jgiven.spock

import com.google.common.reflect.TypeToken
import com.tngtech.jgiven.annotation.DoNotIntercept
import com.tngtech.jgiven.impl.Scenario
import com.tngtech.jgiven.junit.JGivenClassRule
import com.tngtech.jgiven.spock.junit.JGivenSpockMethodRule
import net.bytebuddy.ByteBuddy
import net.bytebuddy.description.annotation.AnnotationDescription
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy
import net.bytebuddy.implementation.SuperMethodCall
import net.bytebuddy.matcher.ElementMatchers
import org.junit.ClassRule
import org.junit.Rule
import spock.lang.Shared
import spock.lang.Specification

/**
* ScenarioSpec to use JGiven with Spock2 Framework
*
* @since 1.2.0
*/
class ScenarioSpec<GIVEN, WHEN, THEN> extends Specification {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add javadoc and an @since annotation here aswell? After all, the entire module will only be available from 1.2.0 onwards

@ClassRule @Shared JGivenClassRule writerRule = new JGivenClassRule()
@Rule JGivenSpockMethodRule scenarioRule = new JGivenSpockMethodRule(createScenario())

GIVEN given() {
getScenario().given()
}

WHEN when() {
getScenario().when()
}

THEN then() {
getScenario().then()
}

Scenario<GIVEN, WHEN, THEN> getScenario() {
(Scenario<GIVEN, WHEN, THEN>) scenarioRule.getScenario()
}

Scenario<GIVEN, WHEN, THEN> createScenario() {
Class<GIVEN> givenClass = addDoNotInterceptToMetaClass(new TypeToken<GIVEN>(getClass()) {}.getRawType())
Class<WHEN> whenClass = addDoNotInterceptToMetaClass(new TypeToken<WHEN>(getClass()) {}.getRawType())
Class<THEN> thenClass = addDoNotInterceptToMetaClass(new TypeToken<THEN>(getClass()) {}.getRawType())

new Scenario<GIVEN, WHEN, THEN>(givenClass, whenClass, thenClass)
}

private <T> Class<T> addDoNotInterceptToMetaClass(Class<T> clazz) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can understand why this exists, but do you happen to know, why it wasn't needed in the spock1 Package?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is related with Groovy 3 vs Groovy 2
The Generated class of MetaClass comes as a method to intercept

AnnotationDescription doNotIntercept = AnnotationDescription.Builder.ofType(DoNotIntercept.class).build()
def clazzA = clazz.metaClass.getTheClass()
new ByteBuddy()
.subclass(clazzA)
.method(ElementMatchers.named("getMetaClass"))
.intercept(SuperMethodCall.INSTANCE)
.annotateMethod(doNotIntercept)
.make()
.load(clazzA.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
.getLoaded() as Class<T>
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.tngtech.jgiven.spock.junit;

import com.tngtech.jgiven.impl.ScenarioBase;
import com.tngtech.jgiven.junit.JGivenMethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import spock.lang.Specification;

/**
* JUnit Rule to enable JGiven with Spock2
*
* @since 1.2.0
*/
public class JGivenSpockMethodRule extends JGivenMethodRule {

/**
* @since 1.2.0
*/
public JGivenSpockMethodRule(ScenarioBase scenario) {
super(scenario);
}

@Override
protected void starting(Statement base, FrameworkMethod testMethod, Object target) {
super.starting(base, testMethod, target);
scenario.getScenarioModel().setDescription(methodNameFromSpec(target));
}

private String methodNameFromSpec(Object target) {
return ((Specification) target).getSpecificationContext().getCurrentIteration().getParent().getDisplayName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.tngtech.jgiven.spock

import com.tngtech.jgiven.annotation.ExtendedDescription
import com.tngtech.jgiven.spock.stages.Given
import com.tngtech.jgiven.spock.stages.Then
import com.tngtech.jgiven.spock.stages.When

class ShinySpockJGivenShould extends ScenarioSpec<Given, When, Then> {

def "something should happen"() {
expect:

given().some_state()
when().some_action()
then().some_outcome()

assert scenario.scenarioModel.description == "something should happen"
}

def "be some able to use params"() {
expect:

given().some_state_$("param")
when().some_action()
then().some_outcome()

assert scenario.scenarioModel.scenarioCases.first().getStep(0).words.join(" ") == "Given some state param"
}

@ExtendedDescription("more details")
def "be able to have extended descriptions"() {
expect:

given().some_state()
when().some_action()
then().some_outcome()

assert scenario.scenarioModel.extendedDescription == "more details"
}

def "be able to use tables #param"() {
expect:
given().some_state_$(param)
when().some_action()
then().some_outcome()

assert scenario.scenarioModel.getDescription() == "be able to use tables #param"

where:
param | _
"param" | _
"word param" | _
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.tngtech.jgiven.spock.stages

import com.tngtech.jgiven.Stage
import com.tngtech.jgiven.annotation.As

class Given extends Stage<Given> {

Given some_state() {
self()
}

def some_state_$(String param) {
self()
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.tngtech.jgiven.spock.stages

import com.tngtech.jgiven.Stage

class Then extends Stage<Then> {

Then some_outcome() {
assert true
self()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.tngtech.jgiven.spock.stages

import com.tngtech.jgiven.Stage

class When extends Stage<When> {

When some_action() {
self()
}
}
4 changes: 2 additions & 2 deletions jgiven-timing/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ description = "Module for injecting automated performance analysis for test meth
dependencies {
implementation project(":jgiven-core")
implementation("com.google.guava:guava:$guavaVersion")
implementation "net.bytebuddy:byte-buddy-gradle-plugin:$bytebuddyVersion"
implementation "net.bytebuddy:byte-buddy-agent:$bytebuddyVersion"
implementation "net.bytebuddy:byte-buddy-gradle-plugin:$byteBuddyVersion"
implementation "net.bytebuddy:byte-buddy-agent:$byteBuddyVersion"
testImplementation("com.google.guava:guava-testlib:$guavaVersion")
testImplementation 'org.mockito:mockito-inline:4.0.0'
}
Expand Down
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ include ':jgiven-core',
':jgiven-maven-plugin',
':jgiven-junit',
':jgiven-spock',
':jgiven-spock2',
':jgiven-testng',
':jgiven-spring',
':jgiven-spring-junit4',
Expand Down