diff --git a/CHANGELOG.md b/CHANGELOG.md index 88e08e90d2a..91b81c91cc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # v0.10.0 +## New Features + +### Nested Steps + +Steps can now have nested steps that are shown in the report. This is done by annotating parent steps with the new `@NestedSteps` annotation. [#17](https://github.com/TNG/JGiven/issues/17) [PR #174](https://github.com/TNG/JGiven/pull/174) Thanks to albertofaci! + +## Fixed Issues + * Fixed the issue that exceptions called within step methods are captured [#173](https://github.com/TNG/JGiven/issues/173) # v0.9.5 diff --git a/jgiven-core/src/main/java/com/tngtech/jgiven/impl/ScenarioModelBuilder.java b/jgiven-core/src/main/java/com/tngtech/jgiven/impl/ScenarioModelBuilder.java index 218a5a5cf23..36acd119dd0 100644 --- a/jgiven-core/src/main/java/com/tngtech/jgiven/impl/ScenarioModelBuilder.java +++ b/jgiven-core/src/main/java/com/tngtech/jgiven/impl/ScenarioModelBuilder.java @@ -315,8 +315,33 @@ public void stepMethodFinished( long durationInNanos, boolean hasNestedSteps ) { currentStep.setDurationInNanos( durationInNanos ); } if( hasNestedSteps ) { + if( currentStep.getStatus() != StepStatus.FAILED ) { + currentStep.setStatus( getStatusFromNestedSteps( currentStep.getNestedSteps() ) ); + } parentSteps.pop(); } + + if( !parentSteps.empty() ) { + currentStep = parentSteps.peek(); + } else { + currentStep = null; + } + } + + private StepStatus getStatusFromNestedSteps( List nestedSteps ) { + StepStatus status = StepStatus.PASSED; + for( StepModel nestedModel : nestedSteps ) { + StepStatus nestedStatus = nestedModel.getStatus(); + + switch( nestedStatus ) { + case FAILED: + return StepStatus.FAILED; + case PENDING: + status = StepStatus.PENDING; + break; + } + } + return status; } @Override @@ -609,23 +634,4 @@ public ScenarioCaseModel getScenarioCaseModel() { return scenarioCaseModel; } - private static class StepAndMethod { - - StepModel stepModel; - Method method; - - private StepAndMethod( Method method, StepModel stepModel ) { - this.method = method; - this.stepModel = stepModel; - } - - public StepModel getStepModel() { - return stepModel; - } - - public Method getMethod() { - return method; - } - } - } diff --git a/jgiven-core/src/main/java/com/tngtech/jgiven/report/text/PlainTextScenarioWriter.java b/jgiven-core/src/main/java/com/tngtech/jgiven/report/text/PlainTextScenarioWriter.java index b869755446c..9334d41bc27 100644 --- a/jgiven-core/src/main/java/com/tngtech/jgiven/report/text/PlainTextScenarioWriter.java +++ b/jgiven-core/src/main/java/com/tngtech/jgiven/report/text/PlainTextScenarioWriter.java @@ -92,10 +92,10 @@ public void visit( StepModel stepModel ) { @Override public void visit( StepModel stepModel ) { - printStep( stepModel, 0 ); + printStep( stepModel, 0, false ); } - private void printStep( StepModel stepModel, int depth ) { + private void printStep( StepModel stepModel, int depth, boolean showPassed ) { List words = stepModel.words; String introString = getIntroString( words, depth ); @@ -119,6 +119,8 @@ private void printStep( StepModel stepModel, int depth ) { } else if( stepModel.isFailed() ) { rest = withColor( Color.RED, true, Attribute.INTENSITY_FAINT, rest ); rest += withColor( Color.RED, true, Attribute.INTENSITY_BOLD, " (failed)" ); + } else if( showPassed ) { + rest += " (passed)"; } writer.println( introString + rest ); @@ -153,7 +155,7 @@ private String getIntroString( List words, int depth ) { private void printNestedSteps( StepModel stepModel, int depth ) { for( StepModel nestedStepModel : stepModel.getNestedSteps() ) { - printStep( nestedStepModel, depth + 1 ); + printStep( nestedStepModel, depth + 1, stepModel.getStatus() == StepStatus.FAILED ); } } diff --git a/jgiven-core/src/test/java/com/tngtech/jgiven/report/text/PlainTextReporterTest.java b/jgiven-core/src/test/java/com/tngtech/jgiven/report/text/PlainTextReporterTest.java index 7cd02d6b2a3..934f94a25c1 100644 --- a/jgiven-core/src/test/java/com/tngtech/jgiven/report/text/PlainTextReporterTest.java +++ b/jgiven-core/src/test/java/com/tngtech/jgiven/report/text/PlainTextReporterTest.java @@ -19,6 +19,7 @@ import com.tngtech.jgiven.annotation.Quoted; import com.tngtech.jgiven.base.ScenarioTestBase; import com.tngtech.jgiven.format.BooleanFormatter; +import com.tngtech.jgiven.report.model.StepModel; /** * Please note that we do explicitly not use the ScenarioTest class for JUnit, @@ -103,7 +104,7 @@ public void missing_intro_words_are_filled_with_spaces() throws UnsupportedEncod } @Test - public void nested_steps_are_displayed_in_the_report() throws UnsupportedEncodingException { + public void nested_steps_are_displayed_in_the_report() throws Throwable { getScenario().startScenario( "test" ); given().something_with_nested_steps(); @@ -111,20 +112,25 @@ public void nested_steps_are_displayed_in_the_report() throws UnsupportedEncodin when().something_happens(); then().something_has_happen() - .something_else_not(); + .something_else_not(); String string = PlainTextReporter.toString( getScenario().getScenarioModel() ); assertThat( string.replaceAll( System.getProperty( "line.separator" ), "\n" ) ) - .contains( "" - + " Scenario: Test\n" - + "\n" - + " Given something with nested steps\n" - + " | Given something\n" - + " | And something else\n" - + " When something happens\n" - + " Then something has happen\n" - + " something else not" - ); + .contains( "" + + " Scenario: Test\n" + + "\n" + + " Given something with nested steps\n" + + " | Given something\n" + + " | And something else\n" + + " When something happens\n" + + " Then something has happen\n" + + " something else not" + ); + + StepModel parentStep = getScenario().getScenarioModel().getScenarioCases().get( 0 ).getStep( 0 ); + long nestedDurations = parentStep.getNestedSteps().get( 0 ).getDurationInNanos() + + parentStep.getNestedSteps().get( 1 ).getDurationInNanos(); + assertThat( parentStep.getDurationInNanos() ).isGreaterThanOrEqualTo( nestedDurations ); } @Test @@ -136,26 +142,26 @@ public void multilevel_nested_steps_are_displayed_in_the_report() throws Unsuppo when().something_happens(); then().something_has_happen() - .something_else_not(); + .something_else_not(); String string = PlainTextReporter.toString( getScenario().getScenarioModel() ); assertThat( string.replaceAll( System.getProperty( "line.separator" ), "\n" ) ) - .contains( "" - + " Scenario: Test\n" - + "\n" - + " Given something with multilevel nested steps\n" - + " | Given something with nested steps\n" - + " | | Given something\n" - + " | | And something else\n" - + " | And something further\n" - + " When something happens\n" - + " Then something has happen\n" - + " something else not" - ); + .contains( "" + + " Scenario: Test\n" + + "\n" + + " Given something with multilevel nested steps\n" + + " | Given something with nested steps\n" + + " | | Given something\n" + + " | | And something else\n" + + " | And something further\n" + + " When something happens\n" + + " Then something has happen\n" + + " something else not" + ); } @Test - public void nested_step_failures_appear_in_the_top_level_enclosing_step() throws UnsupportedEncodingException { + public void nested_step_failures_appear_in_the_top_level_enclosing_step() throws Throwable { getScenario().startScenario( "test" ); given().something_with_nested_steps_that_fails(); @@ -163,20 +169,20 @@ public void nested_step_failures_appear_in_the_top_level_enclosing_step() throws when().something_happens(); then().something_has_happen() - .something_else_not(); + .something_else_not(); String string = PlainTextReporter.toString( getScenario().getScenarioModel() ); assertThat( string.replaceAll( System.getProperty( "line.separator" ), "\n" ) ) - .contains( "" - + " Scenario: Test\n" - + "\n" - + " Given something with nested steps that fails\n" - + " | Given something\n" - + " | And something else that fails (failed)\n" - + " When something happens (skipped)\n" - + " Then something has happen (skipped)\n" - + " something else not (skipped)" - ); + .contains( "" + + " Scenario: Test\n" + + "\n" + + " Given something with nested steps that fails (failed)\n" + + " | Given something (passed)\n" + + " | And something else that fails (failed)\n" + + " When something happens (skipped)\n" + + " Then something has happen (skipped)\n" + + " something else not (skipped)" + ); } @Test