
net.thucydides.core.model.TestStep Maven / Gradle / Ivy
The newest version!
package net.thucydides.core.model;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import net.thucydides.core.guice.Injectors;
import net.thucydides.core.pages.SystemClock;
import net.thucydides.core.screenshots.ScreenshotAndHtmlSource;
import net.thucydides.core.steps.StepFailureException;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static ch.lambdaj.Lambda.*;
import static net.thucydides.core.model.TestResult.*;
/**
* An acceptance test run is made up of test steps.
* Test steps can be either concrete steps or groups of steps.
* Each concrete step should represent an action by the user, and (generally) an expected outcome.
* A test step is described by a narrative-style phrase (e.g. "the user clicks
* on the 'Search' button', "the user fills in the registration form', etc.).
* A screenshot is stored for each step.
*
* @author johnsmart
*
*/
public class TestStep {
private int number;
private String description;
private long duration;
private long startTime;
private List screenshots = new ArrayList<>();
private FailureCause exception;
private TestResult result;
private List children = new ArrayList<>();
public TestStep() {
startTime = now().getMillis();
}
protected void setNumber(int number) {
this.number = number;
}
private SystemClock getSystemClock() {
return Injectors.getInjector().getInstance(SystemClock.class);
}
private DateTime now() {
return getSystemClock().getCurrentTime();
}
public static TestStepBuilder forStepCalled(String description) {
return new TestStepBuilder(description);
}
public boolean hasScreenshots() {
return !getScreenshots().isEmpty();
}
protected List children() {
return children;
}
public int renumberFrom(int count) {
setNumber(count++);
if (hasChildren()) {
count = renumberChildrenFrom(count);
}
return count;
}
private int renumberChildrenFrom(int count) {
for(TestStep step :children) {
count = step.renumberFrom(count);
}
return count;
}
public static class TestStepBuilder {
private final String description;
public TestStepBuilder(String description) {
this.description = description;
}
public TestStep withResult(TestResult result) {
TestStep step = new TestStep(description);
step.setResult(result);
return step;
}
}
@Override
public String toString() {
if (!hasChildren()) {
return description;
} else {
String childDescriptions = join(extract(children, on(TestStep.class).toString()));
return description + " [" + childDescriptions + "]";
}
}
public TestStep(final String description) {
this();
this.description = description;
}
public TestStep(final DateTime startTime, final String description) {
this();
this.startTime = startTime.getMillis();
this.description = description;
}
public TestStep startingAt(DateTime time) {
TestStep newTestStep = copyOfThisTestStep();
newTestStep.startTime = time.getMillis();
return newTestStep;
}
@Override
public TestStep clone() {
TestStep newTestStep = new TestStep();
newTestStep.description = description;
newTestStep.startTime = startTime;
newTestStep.duration = duration;
newTestStep.screenshots = Lists.newArrayList(screenshots);
newTestStep.exception = exception;
newTestStep.result = result;
newTestStep.number = number;
newTestStep.children = Lists.newArrayList(children);
return newTestStep;
}
protected TestStep copyOfThisTestStep() {
return this.clone();
}
public void recordDuration() {
setDuration(now().getMillis() - startTime);
}
public int getNumber() {
return number;
}
public void setDescription(final String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public List getChildren() {
return ImmutableList.copyOf(children);
}
public List getScreenshots() {
return ImmutableList.copyOf(screenshots);
}
public ScreenshotAndHtmlSource getFirstScreenshot() {
if ((screenshots != null) && (!screenshots.isEmpty())) {
return screenshots.get(0);
} else {
return null;
}
}
public boolean needsScreenshots() {
return (!isAGroup() && getScreenshots() != null);
}
/**
* Each test step has a result, indicating the outcome of this step.
* @param result The test outcome associated with this step.
*/
public void setResult(final TestResult result) {
this.result = result;
}
public TestResult getResult() {
if (isAGroup() && !groupResultOverridesChildren()) {
return (result != null) ? TestResultList.of(result, getResultFromChildren()).getOverallResult() : getResultFromChildren();
//return getResultFromChildren();
} else {
return getResultFromThisStep();
}
}
private TestResult getResultFromThisStep() {
if (result != null) {
return result;
} else {
return TestResult.PENDING;
}
}
private boolean groupResultOverridesChildren() {
return ((result == SKIPPED) || (result == IGNORED) || (result == PENDING));
}
private TestResult getResultFromChildren() {
TestResultList resultList = TestResultList.of(getChildResults());
return resultList.getOverallResult();
}
private List getChildResults() {
List results = new ArrayList<>();
for (TestStep step : getChildren()) {
results.add(step.getResult());
}
return results;
}
public Boolean isSuccessful() {
return getResult() == SUCCESS;
}
public Boolean isFailure() {
return getResult() == FAILURE;
}
public Boolean isError() {
return getResult() == ERROR;
}
public Boolean isIgnored() {
return getResult() == IGNORED;
}
public Boolean isSkipped() {
return getResult() == SKIPPED;
}
public Boolean isPending() {
return getResult() == PENDING;
}
public void setDuration(final long duration) {
this.duration = duration;
}
public long getDuration() {
return duration;
}
public double getDurationInSeconds() {
return TestDuration.of(duration).inSeconds();
}
/**
* Indicate that this step failed with a given error.
* @param cause why the test failed.
*/
public void failedWith(final Throwable cause) {
this.exception = new RootCauseAnalyzer(cause).getRootCause();
setResult(new FailureAnalysis().resultFor(this.exception.toException()));
}
public String getErrorMessage() {
return (exception != null) ? exception.getMessage() : "";
}
/**
* The test has been aborted (marked as pending or ignored) for a reason described in the exception.
*/
public void testAborted(final Throwable exception) {
new RootCauseAnalyzer(exception).getRootCause();
}
private String errorMessageFrom(final Throwable error) {
return (error.getCause() != null) ? error.getCause().getMessage() : error.getMessage();
}
public String getShortErrorMessage() {
return new ErrorMessageFormatter(getErrorMessage()).getShortErrorMessage();
}
public FailureCause getException() {
return exception;
}
public List extends TestStep> getFlattenedSteps() {
List flattenedSteps = new ArrayList<>();
for(TestStep child : getChildren()) {
flattenedSteps.add(child);
if (child.isAGroup()) {
flattenedSteps.addAll(child.getFlattenedSteps());
}
}
return flattenedSteps;
}
public boolean isAGroup() {
return hasChildren();
}
public TestStep addChildStep(final TestStep step) {
children.add(step);
return this;
}
public boolean hasChildren() {
return !children.isEmpty();
}
public Collection extends TestStep> getLeafTestSteps() {
List leafSteps = new ArrayList<>();
for(TestStep child : getChildren()) {
if (child.isAGroup()) {
leafSteps.addAll(child.getLeafTestSteps());
} else {
leafSteps.add(child);
}
}
return leafSteps;
}
public TestStep addScreenshot(ScreenshotAndHtmlSource screenshotAndHtmlSource) {
if (thisIsANew(screenshotAndHtmlSource)) {
screenshots.add(screenshotAndHtmlSource);
}
return this;
}
private boolean thisIsANew(ScreenshotAndHtmlSource screenshotAndHtmlSource) {
if (screenshots.isEmpty()) {
return true;
} else {
ScreenshotAndHtmlSource latestScreenshotAndHtmlSource = screenshots.get(screenshots.size() - 1);
return !latestScreenshotAndHtmlSource.equals(screenshotAndHtmlSource);
}
}
public long getStartTime() {
return startTime;
}
public int getScreenshotCount() {
return screenshots.size();
}
public void removeScreenshot(int index) {
screenshots.remove(index);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TestStep)) return false;
TestStep testStep = (TestStep) o;
if (duration != testStep.duration) return false;
if (number != testStep.number) return false;
if (startTime != testStep.startTime) return false;
// TODO
// if (exception != null ? !exceptionsAreEqual(exception, testStep.exception) : testStep.exception != null) return false;
if (!children.equals(testStep.children)) return false;
if (!description.equals(testStep.description)) return false;
if (result != testStep.result) return false;
return !(screenshots != null ? !screenshots.equals(testStep.screenshots) : testStep.screenshots != null);
}
private boolean exceptionsAreEqual(Throwable exception, Throwable otherException) {
if ((exception == null) && (otherException == null)) {
return true;
}
return (StringUtils.equals(exception.getMessage(), otherException.getMessage())
&& (exceptionsAreEqual(exception.getCause(), otherException.getCause())));
}
@Override
public int hashCode() {
int result1 = number;
result1 = 31 * result1 + description.hashCode();
result1 = 31 * result1 + (int) (duration ^ (duration >>> 32));
result1 = 31 * result1 + (int) (startTime ^ (startTime >>> 32));
result1 = 31 * result1 + (screenshots != null ? screenshots.hashCode() : 0);
result1 = 31 * result1 + (exception != null ? exception.hashCode() : 0);
result1 = 31 * result1 + result.hashCode();
result1 = 31 * result1 + children.hashCode();
return result1;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy