Skip to content

Commit

Permalink
refactor: Decoupled serenity-model and serenity-core from JUnit (4)
Browse files Browse the repository at this point in the history
The transitive dependency on JUnit 4 can now be excluded when depending on Serenity (but it is still there to preserve backwards compatibility)
  • Loading branch information
amohrig-kn committed Nov 1, 2019
1 parent cce8f92 commit 904150f
Show file tree
Hide file tree
Showing 19 changed files with 624 additions and 175 deletions.
4 changes: 3 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@
*.otf binary
*.pages binary
*driver binary
*.woff binary
*.woff binary
*.woff2 binary
*.exe
6 changes: 4 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ subprojects {
options.addStringOption('debug')
options.addStringOption('Xdoclint:none')
options.encoding = 'UTF-8'
classpath = configurations.compile
classpath = configurations.compileClasspath
}

dokka {
Expand Down Expand Up @@ -272,7 +272,9 @@ subprojects {
testCompile "org.hamcrest:hamcrest-library:${hamcrestVersion}"
testCompile "org.hamcrest:hamcrest-core:${hamcrestVersion}"

testCompile("org.codehaus.groovy:groovy-all:${groovyVersion}")
testCompile("org.codehaus.groovy:groovy-all:${groovyVersion}") {
exclude group: "org.junit.jupiter"
}
testCompile("org.spockframework:spock-core:${spockVersion}") {
exclude group: "junit"
exclude group: "org.codehaus.groovy"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import net.serenitybdd.core.environment.*;
import net.thucydides.core.configuration.*;
import net.thucydides.core.requirements.SerenityTestCaseFinder;
import net.thucydides.core.webdriver.*;
import org.apache.commons.lang3.StringUtils;
import org.junit.runner.*;
import org.openqa.selenium.*;

import java.util.*;
Expand All @@ -14,13 +14,14 @@

/**
* Utility class used to inject fields into a test case.
* @author johnsmart
*
* @author johnsmart
*/
public final class TestCaseAnnotations {

private final Object testCase;
private final DriverConfiguration configuration;
private static final SerenityTestCaseFinder serenityTestCaseFinder = new SerenityTestCaseFinder();

public TestCaseAnnotations(final Object testCase, WebDriverConfiguration configuration) {
this.testCase = testCase;
Expand All @@ -46,15 +47,15 @@ public void injectDriver(final WebDriver driver) {
}

public void injectDrivers(final WebdriverManager webdriverManager) {
injectDrivers(ThucydidesWebDriverSupport.getDriver(),webdriverManager);
injectDrivers(ThucydidesWebDriverSupport.getDriver(), webdriverManager);
}

public void injectDrivers(final WebDriver defaultDriver, final WebdriverManager webdriverManager) {
List<ManagedWebDriverAnnotatedField> webDriverFields = findAnnotatedFields(testCase.getClass());
int driverCount = 1;

String suffix = "";
for(ManagedWebDriverAnnotatedField webDriverField : webDriverFields) {
for (ManagedWebDriverAnnotatedField webDriverField : webDriverFields) {
String driverRootName = isNotEmpty(webDriverField.getDriver()) ? webDriverField.getDriver() : configuredDriverType();
String driverName = driverRootName + suffix;
String driverOptions = webDriverField.getOptions();
Expand All @@ -74,8 +75,8 @@ public void injectDrivers(final WebDriver defaultDriver, final WebdriverManager
private WebDriver requestedDriverFrom(WebdriverManager webdriverManager, String fieldName, String driverName, String driverOptions) {

return RequestedDrivers.withEnvironmentVariables(configuration.getEnvironmentVariables())
.andWebDriverManager(webdriverManager)
.requestedDriverFor(fieldName, driverName, driverOptions);
.andWebDriverManager(webdriverManager)
.requestedDriverFor(fieldName, driverName, driverOptions);
}

private String configuredDriverType() {
Expand All @@ -102,7 +103,6 @@ public boolean isUniqueSession() {
return isUniqueSession(testCase.getClass());
}


public static boolean isUniqueSession(Class<?> testClass) {
ManagedWebDriverAnnotatedField webDriverField = findFirstAnnotatedField(testClass);
return webDriverField.isUniqueSession();
Expand All @@ -122,8 +122,7 @@ public static boolean shouldUsePersistantStepLibraries(Class<?> testClass) {
}

public static boolean isASerenityTestCase(Class<?> testClass) {
return (testClass != null)
&& (testClass.getAnnotation(RunWith.class) != null)
&& (testClass.getAnnotation(RunWith.class).value().toString().contains("Serenity") || testClass.getAnnotation(RunWith.class).value().toString().contains("Thucydides"));
return serenityTestCaseFinder.isSerenityTestCase(testClass);
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package net.thucydides.core.annotations;

import org.junit.runner.Runner;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
import net.thucydides.core.steps.interception.DynamicExampleStepInterceptionListener;
import net.thucydides.core.steps.interception.StepInterceptionListener;
import net.thucydides.core.util.EnvironmentVariables;
import net.thucydides.core.util.JUnitAdapter;

import org.apache.commons.lang3.StringUtils;
import org.junit.internal.AssumptionViolatedException;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -91,7 +92,7 @@ private boolean baseClassMethod(final Method method, Object obj) {
Class callingClass = obj.getClass();
boolean isACoreLanguageMethod = (OBJECT_METHODS.contains(method.getName()));
boolean methodDoesNotComeFromThisClassOrARelatedParentClass = !declaredInSameDomain(method, callingClass);
boolean isSilentMethod = isSilent(callingClass, method, obj);
boolean isSilentMethod = isSilent(callingClass, method, obj);
return (isACoreLanguageMethod || methodDoesNotComeFromThisClassOrARelatedParentClass || isSilentMethod);
}

Expand All @@ -117,7 +118,6 @@ private boolean isNestedInSilentTask() {
.anyMatch(element -> element.getMethodName().equals("performSilently"));
}


private boolean declaredInSameDomain(Method method, final Class callingClass) {
return domainPackageOf(getRoot(method)).equals(domainPackageOf(callingClass));
}
Expand Down Expand Up @@ -156,17 +156,17 @@ private Method getRoot(Method method) {
}

private Object testStepResult(final Object obj, final Method method,
final Object[] args, final Method zuperMethod) throws Throwable {
final Object[] args, final Method zuperMethod) throws Throwable {

if (!isATestStep(method)) {
return runNormalMethod(obj, method, args, zuperMethod);
}

listeners.forEach( listener -> listener.start(obj, method, args, zuperMethod));
listeners.forEach(listener -> listener.start(obj, method, args, zuperMethod));

Object result = runOrSkipMethod(obj, method, args, zuperMethod);

listeners.forEach( listener -> listener.end(obj, method, args, zuperMethod));
listeners.forEach(listener -> listener.end(obj, method, args, zuperMethod));

return result;
}
Expand Down Expand Up @@ -235,7 +235,7 @@ private Object runIfNestedMethodsShouldBeRun(Object obj, Method method, Object[]
}

private boolean shouldRunNestedMethodsIn(Method method) {
return !(TestAnnotations.shouldSkipNested(method) || shouldSkipNestedIn(method.getDeclaringClass()));
return !(TestAnnotations.shouldSkipNested(method) || shouldSkipNestedIn(method.getDeclaringClass()));
}

private boolean shouldSkipNestedIn(Class testStepClass) {
Expand Down Expand Up @@ -302,7 +302,7 @@ Object appropriateReturnObject(final Object obj, final Method method) {
private Object mockedReturnObjectFor(Method method) {
try {
return Mockito.mock(method.getReturnType());
} catch(RuntimeException tooHardToMockLetsJustCallItQuits) {
} catch (RuntimeException tooHardToMockLetsJustCallItQuits) {
return null;
}
}
Expand All @@ -313,22 +313,22 @@ private boolean returnTypeIsPrimativeFor(Method method) {

private Object primativeDefaultValueFor(Method method) {
switch (returnTypeOf(method)) {
case VOID:
return null;
case STRING:
return "";
case LONG:
return 0L;
case INTEGER:
return 0;
case FLOAT:
return 0.0F;
case DOUBLE:
return 0.0D;
case BOOLEAN:
return Boolean.FALSE;
default:
return null;
case VOID:
return null;
case STRING:
return "";
case LONG:
return 0L;
case INTEGER:
return 0;
case FLOAT:
return 0.0F;
case DOUBLE:
return 0.0D;
case BOOLEAN:
return Boolean.FALSE;
default:
return null;
}
}

Expand Down Expand Up @@ -392,7 +392,6 @@ public void reportMethodError(Throwable generalException, Object obj, Method met
notifyOfStepFailure(obj, method, args, assertionError);
}


private boolean isAnnotatedWithAValidStepAnnotation(final Method method) {
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
Expand All @@ -416,7 +415,7 @@ private boolean isIgnored(final Method method) {
}

private Object runTestStep(final Object obj, final Method method,
final Object[] args, final Method zuperMethod) throws Throwable {
final Object[] args, final Method zuperMethod) throws Throwable {

String callingClass = testContext();
LOGGER.debug("STARTING STEP: {} - {}", callingClass, StepName.fromStepAnnotationIn(method).orElse(method.getName()));
Expand All @@ -428,12 +427,14 @@ private Object runTestStep(final Object obj, final Method method,
error = failedAssertion;
logStepFailure(obj, method, args, failedAssertion);
result = appropriateReturnObject(obj, method);
} catch (AssumptionViolatedException assumptionFailed) {
result = appropriateReturnObject(obj, method);
} catch (Throwable testErrorException) {
error = SerenityManagedException.detachedCopyOf(testErrorException);
logStepFailure(obj, method, args, forError(error).convertToAssertion());
result = appropriateReturnObject(obj, method);
if (JUnitAdapter.isAssumptionViolatedException(testErrorException)) {
result = appropriateReturnObject(obj, method);
} else {
error = SerenityManagedException.detachedCopyOf(testErrorException);
logStepFailure(obj, method, args, forError(error).convertToAssertion());
result = appropriateReturnObject(obj, method);
}
}
return result;
}
Expand All @@ -453,8 +454,12 @@ private Object executeTestStepMethod(Object obj, Method method, Object[] args, M
notifyStepPending(pendingStep.getMessage());
} catch (IgnoredStepException ignoredStep) {
notifyStepIgnored(ignoredStep.getMessage());
} catch (AssumptionViolatedException assumptionViolated) {
notifyAssumptionViolated(assumptionViolated.getMessage());
} catch (Throwable throwable) {
if (JUnitAdapter.isAssumptionViolatedException(throwable)) {
notifyAssumptionViolated(throwable.getMessage());
} else {
throw throwable;
}
}

Preconditions.checkArgument(true);
Expand Down Expand Up @@ -507,9 +512,9 @@ private void notifyStepSkippedFor(final Method method, final Object[] args) {
}

private void notifyOfStepFailure(final Object object, final Method method, final Object[] args,
final Throwable cause) throws Throwable {
final Throwable cause) throws Throwable {
ExecutedStepDescription description = ExecutedStepDescription.of(testStepClass, getTestNameFrom(method, args), args)
.withDisplayedFields(fieldValuesIn(object));
.withDisplayedFields(fieldValuesIn(object));

StepFailure failure = new StepFailure(description, cause);
StepEventBus.getEventBus().stepFailed(failure);
Expand All @@ -524,15 +529,15 @@ private boolean shouldThrowExceptionImmediately() {

private void notifyStepStarted(final Object object, final Method method, final Object[] args) {
ExecutedStepDescription description = ExecutedStepDescription.of(testStepClass, getTestNameFrom(method, args), args)
.withDisplayedFields(fieldValuesIn(object));
.withDisplayedFields(fieldValuesIn(object));
StepEventBus.getEventBus().stepStarted(description);
}

private Map<String, Object> fieldValuesIn(Object object) {
Map<String, Object> coreFieldValues = Fields.of(object).asMap();
Map<String, Object> coreFieldValues = Fields.of(object).asMap();

if (object instanceof HasCustomFieldValues) {
coreFieldValues.putAll( ((HasCustomFieldValues) object).getCustomFieldValues());
coreFieldValues.putAll(((HasCustomFieldValues) object).getCustomFieldValues());
}

return coreFieldValues;
Expand All @@ -541,7 +546,7 @@ private Map<String, Object> fieldValuesIn(Object object) {
private void notifySkippedStepStarted(final Object object, final Method method, final Object[] args) {

ExecutedStepDescription description = ExecutedStepDescription.of(testStepClass, getTestNameFrom(method, args), args)
.withDisplayedFields(fieldValuesIn(object));
.withDisplayedFields(fieldValuesIn(object));
StepEventBus.getEventBus().skippedStepStarted(description);
}

Expand Down
Loading

0 comments on commit 904150f

Please sign in to comment.