Skip to content

Commit

Permalink
feat(#1181): adds TestResultInstanceProvider to support creation of T…
Browse files Browse the repository at this point in the history
…estResults
  • Loading branch information
Thorsten Schlathoelter authored and bbortt committed Jun 25, 2024
1 parent a2e3ec5 commit fcac9de
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.citrusframework;

/**
* Provides methods to create instances of {@link TestResult} for different outcomes of a test case.
* Implementors may decide to create TestResults with specific parameters derived from the {@link TestCase}.
*/
public interface TestResultInstanceProvider {

TestResult createSuccess(TestCase testCase);
TestResult createFailed(TestCase testCase, Throwable throwable);
TestResult createSkipped(TestCase testCase);

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,31 @@

package org.citrusframework;

import static java.lang.String.format;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static org.citrusframework.TestResult.failed;
import static org.citrusframework.TestResult.skipped;
import static org.citrusframework.TestResult.success;
import static org.citrusframework.util.TestUtils.waitForCompletion;

import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.lang3.time.StopWatch;
import org.citrusframework.container.AbstractActionContainer;
import org.citrusframework.container.AfterTest;
import org.citrusframework.container.BeforeTest;
import org.citrusframework.context.TestContext;
import org.citrusframework.exceptions.CitrusRuntimeException;
import org.citrusframework.exceptions.TestCaseFailedException;
import org.citrusframework.spi.ReferenceResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Duration;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.lang.String.format;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static org.citrusframework.TestResult.failed;
import static org.citrusframework.TestResult.skipped;
import static org.citrusframework.TestResult.success;
import static org.citrusframework.util.TestUtils.waitForCompletion;

/**
* Default test case implementation holding a list of test actions to execute. Test case also holds variable definitions and
* performs the test lifecycle such as start, finish, before and after test.
Expand All @@ -51,6 +51,8 @@ public class DefaultTestCase extends AbstractActionContainer implements TestCase

private static final Logger logger = LoggerFactory.getLogger(DefaultTestCase.class);

private static final TestResultInstanceProvider DEFAULT_TEST_RESULT_INSTANCE_PROVIDER = new DefaultTestResultInstanceProvider();

/**
* Further chain of test actions to be executed in any case (success, error)
* Usually used to clean up database in any case of test result
Expand Down Expand Up @@ -114,16 +116,16 @@ public void doExecute(final TestContext context) {
executeAction(actionBuilder.build(), context);
}

testResult = success(getName(), testClass.getName());
testResult = getTestResultInstanceProvider(context).createSuccess(this);
} catch (final TestCaseFailedException e) {
gracefullyStopTimer();
throw e;
} catch (final Exception | AssertionError e) {
testResult = failed(getName(), testClass.getName(), e);
testResult = getTestResultInstanceProvider(context).createFailed(this, e);
throw new TestCaseFailedException(e);
}
} else {
testResult = skipped(getName(), testClass.getName());
testResult = getTestResultInstanceProvider(context).createSkipped(this);
context.getTestListeners().onTestSkipped(this);
}
}
Expand All @@ -142,7 +144,7 @@ public void start(final TestContext context) {

beforeTest(context);
} catch (final Exception | AssertionError e) {
testResult = failed(getName(), testClass.getName(), e);
testResult = getTestResultInstanceProvider(context).createFailed(this, e);
throw new TestCaseFailedException(e);
}
}
Expand Down Expand Up @@ -193,7 +195,7 @@ public void executeAction(final TestAction action, final TestContext context) {
context.getTestActionListeners().onTestActionSkipped(this, action);
}
} catch (final Exception | AssertionError e) {
testResult = failed(getName(), testClass.getName(), e);
testResult = getTestResultInstanceProvider(context).createFailed(this, e);
throw new TestCaseFailedException(e);
} finally {
setExecutedAction(action);
Expand All @@ -219,9 +221,9 @@ public void finish(final TestContext context) {
if (isNull(testResult)) {
if (context.hasExceptions()) {
contextException = context.getExceptions().remove(0);
testResult = failed(getName(), testClass.getName(), contextException);
testResult = getTestResultInstanceProvider(context).createFailed(this, contextException);
} else {
testResult = success(getName(), testClass.getName());
testResult = getTestResultInstanceProvider(context).createSuccess(this);
}
}

Expand All @@ -238,7 +240,7 @@ public void finish(final TestContext context) {
} catch (final TestCaseFailedException e) {
throw e;
} catch (final Exception | AssertionError e) {
testResult = failed(getName(), testClass.getName(), e);
testResult = getTestResultInstanceProvider(context).createFailed(this, e);
throw new TestCaseFailedException(e);
} finally {
if (testResult != null) {
Expand Down Expand Up @@ -298,7 +300,7 @@ private void executeFinalActions(TestContext context) {

if (testResult.isSuccess() && context.hasExceptions()) {
CitrusRuntimeException contextException = context.getExceptions().remove(0);
testResult = failed(getName(), testClass.getName(), contextException);
testResult = getTestResultInstanceProvider(context).createFailed(this, contextException);
throw new TestCaseFailedException(contextException);
}
}
Expand Down Expand Up @@ -381,6 +383,16 @@ public void setFinalActions(final List<TestAction> finalActions) {
this.finalActions = finalActions.stream().map(action -> (TestActionBuilder<?>) () -> action).collect(Collectors.toList());
}

private TestResultInstanceProvider getTestResultInstanceProvider(TestContext context) {

ReferenceResolver referenceResolver = context.getReferenceResolver();
if (referenceResolver != null && referenceResolver.isResolvable(TestResultInstanceProvider.class)) {
return referenceResolver.resolve(TestResultInstanceProvider.class);
}

return DEFAULT_TEST_RESULT_INSTANCE_PROVIDER;
}

@Override
public String toString() {
final StringBuilder stringBuilder = new StringBuilder();
Expand Down Expand Up @@ -527,4 +539,26 @@ public void setTimeout(final long timeout) {
public long getTimeout() {
return timeout;
}

/**
* Default implementation of {@link TestResultInstanceProvider} that provides simple TestResults
* without any parameters.
*/
private static final class DefaultTestResultInstanceProvider implements TestResultInstanceProvider {

@Override
public TestResult createSuccess(TestCase testCase) {
return success(testCase.getName(), testCase.getTestClass().getName());
}

@Override
public TestResult createFailed(TestCase testCase, Throwable throwable) {
return failed(testCase.getName(), testCase.getTestClass().getName(), throwable);
}

@Override
public TestResult createSkipped(TestCase testCase) {
return skipped(testCase.getName(), testCase.getTestClass().getName());
}
}
}

0 comments on commit fcac9de

Please sign in to comment.