Skip to content

Commit

Permalink
Merge pull request #827 from TNG/feature/Issue-373-Improve-testing-fo…
Browse files Browse the repository at this point in the history
…r-jupiter

Feature/issue 373 improve testing for jupiter
  • Loading branch information
l-1squared authored Feb 15, 2022
2 parents f64e7a9 + 1bc9d4a commit 271f94a
Show file tree
Hide file tree
Showing 31 changed files with 650 additions and 206 deletions.
1 change: 1 addition & 0 deletions docs/junit5.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public class JGiven5ScenarioTest
}
}
----
Please note that JGiven is built around each scenario, i.e. test method, having its own test instance. Therefore, we cannot support JUnit's per-class test instance lifecycle. An exception will be thrown if any such attempt is made.

=== Example Project

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,25 @@
import static com.tngtech.jgiven.report.model.ExecutionStatus.FAILED;
import static com.tngtech.jgiven.report.model.ExecutionStatus.SUCCESS;

import java.util.EnumSet;

import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.extension.*;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;

import com.tngtech.jgiven.base.ScenarioTestBase;
import com.tngtech.jgiven.config.AbstractJGivenConfiguration;
import com.tngtech.jgiven.config.ConfigurationUtil;
import com.tngtech.jgiven.exception.JGivenWrongUsageException;
import com.tngtech.jgiven.impl.ScenarioBase;
import com.tngtech.jgiven.impl.ScenarioHolder;
import com.tngtech.jgiven.report.impl.CommonReportHelper;
import com.tngtech.jgiven.report.model.ReportModel;
import java.util.EnumSet;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.TestInstancePostProcessor;

/**
* This extension enables JGiven for JUnit 5 Tests.
Expand All @@ -39,14 +44,16 @@ public class JGivenExtension implements
BeforeAllCallback,
AfterAllCallback,
BeforeEachCallback,
AfterEachCallback {
AfterTestExecutionCallback {

private static final Namespace NAMESPACE = Namespace.create("com.tngtech.jgiven");

private static final String REPORT_MODEL = "report-model";

@Override
public void beforeAll(ExtensionContext context) {
validatePerMethodLifecycle(context);

ReportModel reportModel = new ReportModel();
reportModel.setTestClass(context.getTestClass().get());
if (!context.getDisplayName().equals(context.getTestClass().get().getSimpleName())) {
Expand All @@ -62,6 +69,7 @@ public void beforeAll(ExtensionContext context) {
}
}


@Override
public void afterAll(ExtensionContext context) {
ScenarioHolder.get().removeScenarioOfCurrentThread();
Expand All @@ -75,7 +83,7 @@ public void beforeEach(ExtensionContext context) {
}

@Override
public void afterEach(ExtensionContext context) throws Exception {
public void afterTestExecution(ExtensionContext context) throws Exception {
ScenarioBase scenario = getScenario();
try {
if (context.getExecutionException().isPresent()) {
Expand All @@ -96,10 +104,6 @@ public void afterEach(ExtensionContext context) throws Exception {
}
}

private ScenarioBase getScenario() {
return ScenarioHolder.get().getScenarioOfCurrentThread();
}

@Override
public void postProcessTestInstance(Object testInstance, ExtensionContext context) {
ScenarioBase currentScenario = ScenarioHolder.get().getScenarioOfCurrentThread();
Expand All @@ -125,4 +129,21 @@ public void postProcessTestInstance(Object testInstance, ExtensionContext contex
scenario.getExecutor().readScenarioState(testInstance);
}

private void validatePerMethodLifecycle(ExtensionContext context) {
if (isPerClassLifecycle(context)) {
throw new JGivenWrongUsageException(
"JGiven does not support keeping a test instance over multiple scenarios. Please use Lifecycle '"
+ TestInstance.Lifecycle.PER_METHOD + "'.");
}
}

private boolean isPerClassLifecycle(ExtensionContext context) {
return context.getTestInstanceLifecycle()
.filter(lifecycle -> TestInstance.Lifecycle.PER_CLASS == lifecycle)
.isPresent();
}

private ScenarioBase getScenario() {
return ScenarioHolder.get().getScenarioOfCurrentThread();
}
}
4 changes: 4 additions & 0 deletions jgiven-tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ description = 'JGiven Tests - Contains BDD tests for JGiven written in JGiven'
dependencies {
implementation project(':jgiven-junit')
implementation project(':jgiven-testng')
implementation project(':jgiven-junit5')
implementation project(':jgiven-html5-report')
implementation "junit:junit:$junitVersion"
implementation "org.junit.jupiter:junit-jupiter-api:5.8.2"
implementation "org.junit.jupiter:junit-jupiter-engine:5.8.2"
implementation "org.junit.platform:junit-platform-runner:1.8.2"
implementation "org.testng:testng:$testngVersion"
implementation "com.tngtech.java:junit-dataprovider:$junitDataproviderVersion"
implementation 'com.beust:jcommander:1.82'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.tngtech.jgiven.tags;

import com.tngtech.jgiven.annotation.IsTag;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@FeatureTestFramework
@IsTag( name = "JUnit5",
description = "Tests can be be executed with JUnit5" )
@Retention( RetentionPolicy.RUNTIME )
public @interface FeatureJUnit5 {

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ public GivenTestStage an_exception_is_thrown() {
throw new RuntimeException("Some Exception");
}

public void nothing() {
public GivenTestStage nothing() {
return this;
}

public void a_failed_step(boolean fail) {
public GivenTestStage a_failed_step(boolean fail) {
if (fail) {
throw new IllegalArgumentException();
}
return this;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import com.tngtech.jgiven.junit.ScenarioTest;
import org.junit.Test;

public class GuaranteedFieldRealTest extends ScenarioTest<GuaranteedFieldRealTest.RealGiven, GuaranteedFieldRealTest.RealWhen, GuaranteedFieldRealTest.RealThen> {
public class GuaranteedFieldRealTest extends
ScenarioTest<GuaranteedFieldRealTest.RealGiven, GuaranteedFieldRealTest.RealWhen, GuaranteedFieldRealTest.RealThen> {

@Test
public void a_sample_test() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.tngtech.jgiven.tests;

import com.tngtech.jgiven.exception.JGivenWrongUsageException;
import com.tngtech.jgiven.impl.ScenarioBase;
import com.tngtech.jgiven.impl.ScenarioHolder;
import com.tngtech.jgiven.junit5.JGivenExtension;
import com.tngtech.jgiven.report.model.ReportModel;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import org.junit.jupiter.api.extension.ExtensionContext;

/**
* Extracts the report Model from within the Test context before it gets deleted.
*/
public class JGivenReportExtractingExtension extends JGivenExtension {

private static final Map<Class<?>, ReportModel> modelHolder = new ConcurrentHashMap<>();

public static Optional<ReportModel> getReportModelFor(Class<?> testClass) {
return Optional.ofNullable(modelHolder.get(testClass));
}


@Override
public void afterTestExecution(ExtensionContext context) throws Exception {
Class<?> testClass = context.getTestClass()
.orElseThrow(() -> new JGivenWrongUsageException("tests without test class are not supported yet"));
Optional.ofNullable(ScenarioHolder.get())
.map(ScenarioHolder::getScenarioOfCurrentThread)
.map(ScenarioBase::getModel)
.ifPresent(model -> modelHolder.put(testClass, model));
super.afterTestExecution(context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.tngtech.jgiven.tests;

import com.tngtech.jgiven.base.ScenarioTestBase;
import com.tngtech.jgiven.impl.Scenario;
import com.tngtech.jgiven.report.model.ScenarioCaseModel;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(JGivenReportExtractingExtension.class)
public class JUnit5AfterMethodTests extends ScenarioTestBase<GivenTestStage, WhenTestStage, ThenTestStage> {

private final Scenario<GivenTestStage, WhenTestStage, ThenTestStage> scenario = createScenario();

@Override
public Scenario<GivenTestStage, WhenTestStage, ThenTestStage> getScenario() {
return scenario;
}

@Test
public void a_failing_JUnit_5_test() {
given().nothing();
when().a_step_fails();
then().something_happened();
}

@Test
public void a_succeeding_JUnit5_test() {
given().nothing();
when().something_happens();
then().something_happened();
}

@Test
@Disabled
public void a_skipped_JUnit5_test() {
given().nothing();
when().something_happens();
then().something_happened();
}


@AfterEach
public void modifyScenario() {
getScenario().getModel().getLastScenarioModel().addCase(new ScenarioCaseModel());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import com.tngtech.jgiven.impl.Scenario;
import com.tngtech.jgiven.junit.ScenarioTest;
import com.tngtech.jgiven.impl.ScenarioHolder;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(JGivenReportExtractingExtension.class)
public class ScenarioTestForTesting<GIVEN, WHEN, THEN> extends ScenarioTest<GIVEN,WHEN,THEN> {
@Override
public Scenario<GIVEN, WHEN, THEN> getScenario() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package com.tngtech.jgiven.tests;

import org.junit.Test;
import org.testng.annotations.Listeners;

import com.tngtech.jgiven.annotation.Description;
import com.tngtech.jgiven.junit.ScenarioTest;
import com.tngtech.jgiven.testng.ScenarioTestListener;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.testng.annotations.Listeners;

@Listeners( ScenarioTestListener.class )
@ExtendWith(JGivenReportExtractingExtension.class)
@Description( "Test Description" )
public class TestClassWithDescription extends ScenarioTest<GivenTestStage, WhenTestStage, ThenTestStage> {

@Test
@org.junit.jupiter.api.Test
@org.testng.annotations.Test
public void some_test() {
given().nothing();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package com.tngtech.jgiven.tests;

import com.tngtech.jgiven.testng.ScenarioTestListener;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.extension.ExtendWith;
import org.testng.annotations.Listeners;

import com.tngtech.jgiven.junit.ScenarioTest;
import com.tngtech.jgiven.testng.ScenarioTestListener;

@Listeners( ScenarioTestListener.class )
@ExtendWith(JGivenReportExtractingExtension.class)
public class TestClassWithOnlyIgnoredTests extends ScenarioTestForTesting<GivenTestStage, WhenTestStage, ThenTestStage> {

@Ignore
@Test
@org.junit.jupiter.api.Test
@Disabled
@org.testng.annotations.Test( enabled = false )
public void test() {

Expand Down
Loading

0 comments on commit 271f94a

Please sign in to comment.