Skip to content

Commit

Permalink
Initial implementation of JUnit5 integration (#220)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Schäfer committed Dec 26, 2016
1 parent 94fce51 commit a34f92c
Show file tree
Hide file tree
Showing 36 changed files with 802 additions and 22 deletions.
10 changes: 8 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,18 @@ configure(subprojects) {

}

configure(subprojects.findAll {!it.name.contains("jgiven-junit5")}) {
apply plugin: 'ru.vyarus.animalsniffer'

dependencies {
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
}
}

configure(subprojects.findAll {!it.name.contains("android")}) {
apply plugin: 'checkstyle'
apply plugin: 'java'
apply plugin: 'org.asciidoctor.convert'
apply plugin: 'ru.vyarus.animalsniffer'

dependencies {
compile group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion
Expand All @@ -197,7 +204,6 @@ configure(subprojects.findAll {!it.name.contains("android")}) {
testCompile group: 'org.assertj', name: 'assertj-core', version: assertjVersion
testCompile group: 'com.tngtech.java', name: 'junit-dataprovider', version: junitDataproviderVersion
testCompile group: 'net.java.quickcheck', name: 'quickcheck', version: quickcheckVersion
signature 'org.codehaus.mojo.signature:java16:1.1@signature'
}

sourceCompatibility = targetCompatibility = 1.6
Expand Down
2 changes: 2 additions & 0 deletions docs/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,5 @@ include::spring.adoc[]
include::selenium.adoc[]

include::android.adoc[]

include::junit5.adoc[]
4 changes: 4 additions & 0 deletions docs/intro.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,8 @@ stages classes can be treated as Spring beans.

==== JGiven Android
Provides support for executing JGiven tests on an Android device or emulator.
This is currently in an experimental status.

==== JGiven JUnit 5
This module provides an integration into JUnit 5.x.
This is currently in an experimental status.
86 changes: 86 additions & 0 deletions docs/junit5.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
== JUnit 5 (EXPERIMENTAL)
:javadocurl: http://static.javadoc.io/com.tngtech.jgiven/jgiven-junit5/{version}/com/tngtech/jgiven/junit5

CAUTION: JUnit 5 support is currently in an experimental state.
This means that the API is not completely stable yet and that not all
JGiven and JUnit 5 features are completely supported yet.

=== Known Issues

* Nested tests are all reported under the outer parent test class
* Dynamic tests are not reported at all. As dynamic tests in JUnit 5 do not provide life-cycle
hooks, it is unclear at the moment, whether JGiven will ever support them.

=== Install Dependency
JUnit 5 support is provided by the `jgiven-junit5` dependency.

==== Maven

[source,maven,subs="verbatim,attributes"]
----
<dependency>
<groupId>com.tngtech.jgiven</groupId>
<artifactId>jgiven-junit5</artifactId>
<version>{version}</version>
<scope>test</scope>
</dependency>
----

==== Gradle

[source,gradle,subs="verbatim,attributes"]
----
dependencies {
testCompile("com.tngtech.jgiven:jgiven-junit5:{version}")
}
----

=== Use JGiven with JUnit 5

JGiven support for JUnit 5 is provided by the link:{javadocurl}/JGivenExtension.html[`JGivenExtension`]
JUnit 5 extension. You just annotate your JUnit 5 test class with `@ExtendWith( JGivenExtension.class )`
and JGiven is enabled.

If you just use the extension directly, you have to inject your stage classes by using
the `@ScenarioStage` annotation.

[source,java]
----
@ExtendWith( JGivenExtension.class )
public class JUnit5Test {
@ScenarioStage
MyStage myStage;
@Test
public void my_scenario() {
myStage
.given().some_context()
.when().some_action()
.then().some_outcome();
}
}
----

Alternatively, you can use one of the test base classes link:{javadocurl}/ScenarioTest.html[`ScenarioTest`] or
link:{javadocurl}/SimpleScenarioTest.html[`SimpleScenarioTest`] that provide additional convenience methods
and allows you to specify stage classes by using type parameters:

[source,java]
----
public class JGiven5ScenarioTest
extends ScenarioTest<GivenStage, WhenStage, ThenStage> {
@Test
public void JGiven_works_with_JUnit5() {
given().some_state();
when().some_action();
then().some_outcome();
}
}
----

=== Example Project

You find a complete example project on GitHub: https://github.com/TNG/JGiven/tree/master/example-projects/junit5
6 changes: 6 additions & 0 deletions example-projects/junit5/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# JUnit 5 Example Project

This project shows how JGiven can be used with JUnit 5

1. Run `gradle build`
2. Open `build/reports/jgiven/test/html/index.html`
51 changes: 51 additions & 0 deletions example-projects/junit5/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-M3'
}
}

plugins {
id "com.tngtech.jgiven.gradle-plugin" version "0.13.0"
}

apply plugin: 'org.junit.platform.gradle.plugin'

apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'eclipse'

compileJava {
sourceCompatibility = 1.8
targetCompatibility = 1.8
options.compilerArgs += '-parameters'
options.encoding = 'UTF-8'
}

ext {
junit5Version = '5.0.0-M3'
}

repositories {
mavenLocal()
mavenCentral()
maven {
url "https://oss.sonatype.org/content/repositories/snapshots/"
}
}

dependencies {
testCompile 'com.tngtech.jgiven:jgiven-junit5:latest.integration'
testCompile 'org.junit.jupiter:junit-jupiter-api:' + junit5Version
testCompile 'org.junit.jupiter:junit-jupiter-engine:' + junit5Version
}

junitPlatform {
enableStandardTestTask true
platformVersion = "1.0.0-M3"
}

test.finalizedBy jgivenTestReport
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.tngtech.jgiven.example.projects.junit5;

import com.tngtech.jgiven.Stage;
import com.tngtech.jgiven.annotation.Quoted;
import com.tngtech.jgiven.annotation.ScenarioState;

public class GivenStage extends Stage<GivenStage> {

@ScenarioState
String message;

GivenStage message(@Quoted String message) {
this.message = message;
return self();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.tngtech.jgiven.example.projects.junit5;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import com.tngtech.jgiven.annotation.ScenarioStage;
import com.tngtech.jgiven.junit5.JGivenExtension;

@ExtendWith( JGivenExtension.class )
public class JUnit5Test {

@ScenarioStage
GivenStage givenStage;

@ScenarioStage
WhenStage whenStage;

@ScenarioStage
ThenStage thenStage;

@Test
public void scenario_with_JUnit5() {
givenStage.given().message( "Hello JUnit" );
whenStage.when().handle_message();
thenStage.then().the_result_is( "Hello JUnit 5!" );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.tngtech.jgiven.example.projects.junit5;

import com.tngtech.jgiven.Stage;
import com.tngtech.jgiven.annotation.ScenarioState;
import org.junit.jupiter.api.Assertions;

public class ThenStage extends Stage<ThenStage> {
@ScenarioState(required = true)
String result;

public void the_result_is(String expectedResult) {
Assertions.assertEquals(expectedResult, result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.tngtech.jgiven.example.projects.junit5;

import com.tngtech.jgiven.Stage;
import com.tngtech.jgiven.annotation.ScenarioState;

public class WhenStage extends Stage<WhenStage> {
@ScenarioState(required = true)
String message;

@ScenarioState
String result;

public void handle_message() {
result = message + " 5!";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ public AbstractJGivenConfiguration load( Class<?> key ) throws Exception {

public static AbstractJGivenConfiguration getConfiguration( Class<? extends Object> testClass ) {
JGivenConfiguration annotation = testClass.getAnnotation( JGivenConfiguration.class );
Class<?> configuration;
if( annotation == null ) {
return new DefaultConfiguration();
configuration = DefaultConfiguration.class;
} else {
configuration = annotation.value();
}

try {
return configurations.get( annotation.value() );
return configurations.get( configuration );
} catch( ExecutionException e ) {
throw Throwables.propagate( e.getCause() );
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
package com.tngtech.jgiven.testng;

import com.tngtech.jgiven.impl.ScenarioBase;
package com.tngtech.jgiven.impl;

public class ScenarioHolder {
private final ThreadLocal<ScenarioBase> scenario = new ThreadLocal<ScenarioBase>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ public void scenarioFailed( Throwable e ) {
public void scenarioStarted( Class<?> testClass, Method method, List<NamedArgument> namedArguments ) {
readConfiguration( testClass );
readAnnotations( testClass, method );
scenarioModel.setClassName(testClass.getName());
setParameterNames( getNames( namedArguments ) );

// must come at last
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.tngtech.jgiven.impl.util.ReflectionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,18 +208,22 @@ private static Function<Field, Object> getFieldValueFunction( final Object targe
return new Function<Field, Object>() {
@Override
public Object apply( Field field ) {
makeAccessible( field, "" );
try {
return field.get( target );
} catch( IllegalAccessException e ) {
log.warn(
format( "Not able to access field '%s'." + errorDescription, toReadableString( field ) ), e );
return null;
}
return getFieldValueOrNull(field, target, errorDescription);
}
};
}

public static Object getFieldValueOrNull(Field field, Object target, String errorDescription) {
makeAccessible( field, "" );
try {
return field.get( target );
} catch( IllegalAccessException e ) {
log.warn(
format( "Not able to access field '%s'." + errorDescription, toReadableString( field ) ), e );
return null;
}
}

public static List<Field> getAllNonStaticFields( Class<?> clazz ) {
final List<Field> result = Lists.newArrayList();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ public synchronized void setTagMap( Map<String, Tag> tagMap ) {
}

public synchronized void addScenarioModelOrMergeWithExistingOne( ScenarioModel scenarioModel ) {
scenarioModel.setClassName( getClassName() );
Optional<ScenarioModel> existingScenarioModel = findScenarioModel( scenarioModel.getDescription() );

if( existingScenarioModel.isPresent() ) {
Expand Down Expand Up @@ -192,4 +191,8 @@ public synchronized void setTestClass( Class<?> testClass ) {
public String getName() {
return name;
}

public void setName( String name ) {
this.name = name;
}
}
Loading

0 comments on commit a34f92c

Please sign in to comment.