diff --git a/README.md b/README.md index eaa31f98..41a05534 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,9 @@ Requirements * Redacted some of the output of the config * Passed the name of the running feature and scenario into the context. * RemoteWebDriverFactory sets up additional information to pass though via capabilities (current git branch, version) +* Made the report builder more robust when there are no tests run +* Modified the Substeps exceptions to limit the stack trace +* Improved error message when no tests are run 1.0.5 ----- diff --git a/api/src/main/java/com/technophobia/substeps/model/exception/NoTestsRunException.java b/api/src/main/java/com/technophobia/substeps/model/exception/NoTestsRunException.java new file mode 100644 index 00000000..12032f0e --- /dev/null +++ b/api/src/main/java/com/technophobia/substeps/model/exception/NoTestsRunException.java @@ -0,0 +1,30 @@ +/* + * Copyright Technophobia Ltd 2012 + * + * This file is part of Substeps. + * + * Substeps is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Substeps is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Substeps. If not, see . + */ +package com.technophobia.substeps.model.exception; + +public class NoTestsRunException extends SubstepsException { + + private static final long serialVersionUID = 4050361783327727693L; + + public NoTestsRunException() { + super("No tests executed"); + } + + +} diff --git a/api/src/main/java/com/technophobia/substeps/model/exception/SubstepsException.java b/api/src/main/java/com/technophobia/substeps/model/exception/SubstepsException.java index c25fe342..104cf1e6 100644 --- a/api/src/main/java/com/technophobia/substeps/model/exception/SubstepsException.java +++ b/api/src/main/java/com/technophobia/substeps/model/exception/SubstepsException.java @@ -18,6 +18,10 @@ */ package com.technophobia.substeps.model.exception; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.Arrays; + public class SubstepsException extends RuntimeException { private static final long serialVersionUID = 4647698987295633906L; @@ -38,4 +42,35 @@ public SubstepsException(final Throwable cause) { super(cause); } + @Override + public StackTraceElement[] getStackTrace() { + + StackTraceElement[] original = super.getStackTrace(); + int i = 0; + for (; i < original.length; i++){ + if (original[i].getClassName().contains("substeps")){ + // + } + else { + break; + } + } + + return Arrays.copyOf(original, i + 1); + } + + @Override + public void printStackTrace(PrintStream s) { + StackTraceElement[] elems = getStackTrace(); + setStackTrace(elems); + super.printStackTrace(s); + } + + @Override + public void printStackTrace(PrintWriter s) { + StackTraceElement[] elems = getStackTrace(); + setStackTrace(elems); + + super.printStackTrace(s); + } } diff --git a/core/src/main/java/com/technophobia/substeps/runner/ExecutionNodeRunner.java b/core/src/main/java/com/technophobia/substeps/runner/ExecutionNodeRunner.java index b2727890..eba2c430 100644 --- a/core/src/main/java/com/technophobia/substeps/runner/ExecutionNodeRunner.java +++ b/core/src/main/java/com/technophobia/substeps/runner/ExecutionNodeRunner.java @@ -25,6 +25,7 @@ import com.technophobia.substeps.execution.MethodExecutor; import com.technophobia.substeps.execution.node.*; import com.technophobia.substeps.model.*; +import com.technophobia.substeps.model.exception.NoTestsRunException; import com.technophobia.substeps.runner.builder.ExecutionNodeTreeBuilder; import com.technophobia.substeps.runner.node.RootNodeRunner; import com.technophobia.substeps.runner.setupteardown.SetupAndTearDown; @@ -331,7 +332,7 @@ public RootNode run() { if (!this.nodeExecutionContext.haveTestsBeenRun()) { - final Throwable t = new IllegalStateException("No tests executed"); + final Throwable t = new NoTestsRunException();//IllegalStateException("No tests executed"); SubstepExecutionFailure sef = new SubstepExecutionFailure(t, this.rootNode, ExecutionResult.FAILED); diff --git a/core/src/main/java/com/technophobia/substeps/runner/node/AbstractNodeRunner.java b/core/src/main/java/com/technophobia/substeps/runner/node/AbstractNodeRunner.java index ba64cd92..e6f03e26 100644 --- a/core/src/main/java/com/technophobia/substeps/runner/node/AbstractNodeRunner.java +++ b/core/src/main/java/com/technophobia/substeps/runner/node/AbstractNodeRunner.java @@ -21,6 +21,7 @@ import com.technophobia.substeps.execution.AbstractExecutionNodeVisitor; import com.technophobia.substeps.execution.ExecutionResult; import com.technophobia.substeps.execution.node.IExecutionNode; +import com.technophobia.substeps.execution.node.RootNode; import com.technophobia.substeps.execution.node.RootNodeExecutionContext; import com.technophobia.substeps.model.Scope; import com.technophobia.substeps.model.exception.SubstepsException; @@ -175,8 +176,15 @@ protected boolean addExpectedChildrenFailureIfNoChildren(final NODE_TYPE node, final boolean hasChildren = children != null && !children.isEmpty(); if (!hasChildren) { - context.addFailure(new SubstepExecutionFailure(new IllegalStateException( - "node should have children but doesn't"), node)); + + String msg; + if (node instanceof RootNode){ + msg = "\n\n ** No tests were executed, check Tag configuration in your pom.xml and the tags in the included features **\n\n"; + }else { + msg = "node should have children but doesn't"; + } + + context.addFailure(new SubstepExecutionFailure(new SubstepsRuntimeException(msg), node)); } return hasChildren; diff --git a/core/src/main/scala/org/substeps/report/ReportBuilder.scala b/core/src/main/scala/org/substeps/report/ReportBuilder.scala index b79dc8cc..fcb7f1de 100644 --- a/core/src/main/scala/org/substeps/report/ReportBuilder.scala +++ b/core/src/main/scala/org/substeps/report/ReportBuilder.scala @@ -375,7 +375,11 @@ class ReportBuilder extends IReportBuilder with ReportFrameTemplate with UsageTr val substepNodeDetails = allNodeDetails.filter(nd => nd.nodeType == "SubstepNode") val substepDefsByUniqueMethood = substepNodeDetails.groupBy(_.source.get) - val nextId = allNodeDetails.map(n => n.id).max + 1 + var nextId = allNodeDetails.map(n => n.id) match { + case Nil => 1 + case ids => ids.max + 1 + } + substepDefsByUniqueMethood.map(e => { @@ -430,7 +434,10 @@ class ReportBuilder extends IReportBuilder with ReportFrameTemplate with UsageTr val stepImplsbyUniqueMethood = stepImplNodeDetails.groupBy(_.method.get) - var nextId = allNodeDetails.map(n => n.id).max + 1 + var nextId = allNodeDetails.map(n => n.id) match { + case Nil => 1 + case ids => ids.max + 1 + } val stepImplNodeDetailsToUsages = diff --git a/core/src/test/java/com/technophobia/substeps/runner/ExecutionNodeRunnerTest.java b/core/src/test/java/com/technophobia/substeps/runner/ExecutionNodeRunnerTest.java index 289ab795..0a61e30e 100644 --- a/core/src/test/java/com/technophobia/substeps/runner/ExecutionNodeRunnerTest.java +++ b/core/src/test/java/com/technophobia/substeps/runner/ExecutionNodeRunnerTest.java @@ -25,7 +25,9 @@ import com.technophobia.substeps.execution.ImplementationCache; import com.technophobia.substeps.execution.node.*; import com.technophobia.substeps.model.Arguments; +import com.technophobia.substeps.model.exception.NoTestsRunException; import com.technophobia.substeps.model.exception.SubstepsConfigurationException; +import com.technophobia.substeps.model.exception.SubstepsRuntimeException; import com.technophobia.substeps.model.exception.UnimplementedStepException; import com.technophobia.substeps.runner.setupteardown.Annotations.BeforeAllFeatures; import com.technophobia.substeps.runner.setupteardown.SetupAndTearDown; @@ -38,6 +40,8 @@ import org.junit.Ignore; import org.junit.Test; import org.mockito.Mockito; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.substeps.report.IExecutionResultsCollector; import java.io.File; @@ -119,7 +123,7 @@ public void testParseErrorResultsInFailedTest() { Assert.assertThat(failures.get(0).getThrowableInfo().getMessage(), is(msg)); - Assert.assertThat(failures.get(1).getThrowableInfo().getThrowableClass(), is(IllegalStateException.class.getName())); + Assert.assertThat(failures.get(1).getThrowableInfo().getThrowableClass(), is(NoTestsRunException.class.getName())); Assert.assertThat(failures.get(1).getThrowableInfo().getMessage(), is("No tests executed")); } @@ -157,7 +161,7 @@ public void testSubStepDefinitionMatchesStepImplFailure() { + TestStepImplementations.class.getName() + ".given()] AND matches a sub step definition: [Given something] in [duplicates2.substeps]")); - Assert.assertThat(failures.get(1).getThrowableInfo().getThrowableClass(), is(IllegalStateException.class.getName())); + Assert.assertThat(failures.get(1).getThrowableInfo().getThrowableClass(), is(NoTestsRunException.class.getName())); Assert.assertThat(failures.get(1).getThrowableInfo().getMessage(), is("No tests executed")); } @@ -362,7 +366,7 @@ public void testNoTestsExecutedResultsInTwoFailures() { runner.run(); final List failures = runner.getFailures(); - verify(mockNotifer, times(1)).onNodeFailed(argThat(is(node)), argThat(any(IllegalStateException.class))); + verify(mockNotifer, times(1)).onNodeFailed(argThat(is(node)), argThat(any(NoTestsRunException.class))); // verify(mockNotifer, times(1)).onNodeFailed(argThat(is(node)), argThat(any(SubstepsRuntimeException.class))); Assert.assertFalse("expecting some failures", failures.isEmpty()); @@ -417,11 +421,11 @@ public void testScenarioOutlineFailsWithNoExamples() { Assert.assertThat(failures.size(), is(2)); - Assert.assertThat(failures.get(0).getThrowableInfo().getThrowableClass(), is(IllegalStateException.class.getName())); + Assert.assertThat(failures.get(0).getThrowableInfo().getThrowableClass(), is(SubstepsRuntimeException.class.getName())); Assert.assertThat(failures.get(0).getThrowableInfo().getMessage(), is("node should have children but doesn't")); - Assert.assertThat(failures.get(1).getThrowableInfo().getThrowableClass(), is(IllegalStateException.class.getName())); + Assert.assertThat(failures.get(1).getThrowableInfo().getThrowableClass(), is(NoTestsRunException.class.getName())); Assert.assertThat(failures.get(1).getThrowableInfo().getMessage(), is("No tests executed")); } @@ -574,7 +578,7 @@ public void testBeforeAllFeaturesSetupFailureFailsTheBuild() { Assert.assertTrue("failure should be marked as setup or tear down", failures.get(0).isSetupOrTearDown()); - Assert.assertThat(failures.get(1).getThrowableInfo().getThrowableClass(), is(IllegalStateException.class.getName())); + Assert.assertThat(failures.get(1).getThrowableInfo().getThrowableClass(), is(NoTestsRunException.class.getName())); Assert.assertThat(failures.get(1).getThrowableInfo().getMessage(), is("No tests executed")); } @@ -842,5 +846,17 @@ public void testExecutionNodeTreeBuildingWithScenarioName() { Assert.assertThat(rootNode.getChildren().get(0).getChildren().size(), is(1)); } + private static final Logger log = LoggerFactory.getLogger(ExecutionNodeRunnerTest.class); + + + @Test + public void testNoTestRunException(){ + + Throwable e = new NoTestsRunException(); + + log.debug("an exception: ", e); + } } + +