diff --git a/jgiven-core/src/main/java/com/tngtech/jgiven/annotation/ExpectedScenarioState.java b/jgiven-core/src/main/java/com/tngtech/jgiven/annotation/ExpectedScenarioState.java index 1c95bc56a3f..205b8dd7425 100644 --- a/jgiven-core/src/main/java/com/tngtech/jgiven/annotation/ExpectedScenarioState.java +++ b/jgiven-core/src/main/java/com/tngtech/jgiven/annotation/ExpectedScenarioState.java @@ -18,4 +18,10 @@ @Target( ElementType.FIELD ) public @interface ExpectedScenarioState { Resolution resolution() default Resolution.AUTO; + + /** + * Defines whether this state is required. + * If set to {@code true} and no stage provided this state, the tests will automatically fail. + */ + boolean required() default false; } diff --git a/jgiven-core/src/main/java/com/tngtech/jgiven/annotation/ScenarioState.java b/jgiven-core/src/main/java/com/tngtech/jgiven/annotation/ScenarioState.java index 5f5b5b7d702..dc7da65855e 100644 --- a/jgiven-core/src/main/java/com/tngtech/jgiven/annotation/ScenarioState.java +++ b/jgiven-core/src/main/java/com/tngtech/jgiven/annotation/ScenarioState.java @@ -18,4 +18,10 @@ public enum Resolution { TYPE, NAME, AUTO; } + + /** + * Defines whether this state is required. + * If set to {@code true} and no stage provided this state, the tests will automatically fail. + */ + boolean required() default false; } diff --git a/jgiven-core/src/main/java/com/tngtech/jgiven/impl/inject/ValueInjector.java b/jgiven-core/src/main/java/com/tngtech/jgiven/impl/inject/ValueInjector.java index d3585fe47ce..e9972aa1bc1 100644 --- a/jgiven-core/src/main/java/com/tngtech/jgiven/impl/inject/ValueInjector.java +++ b/jgiven-core/src/main/java/com/tngtech/jgiven/impl/inject/ValueInjector.java @@ -90,6 +90,8 @@ public void updateValues( Object object ) { if( value != null ) { field.set( object, value ); log.debug( "Setting field {} to value {}", field, value ); + } else if( isRequired( field ) ) { + throw new RuntimeException( "TODO Better exception?" ); } } catch( IllegalAccessException e ) { throw new RuntimeException( "Error while updating field " + field, e ); @@ -107,23 +109,19 @@ public void injectValueByName( String name, T value ) { private void updateValue( Field field, Object value ) { Resolution resolution = getResolution( field ); - Class type = field.getType(); if( resolution == Resolution.NAME ) { - String name = field.getName(); - state.updateValueByName( name, value ); + state.updateValueByName( field.getName(), value ); } else { - state.updateValueByType( type, value ); + state.updateValueByType( field.getType(), value ); } } private Object getValue( Field field ) { Resolution resolution = getResolution( field ); - Class type = field.getType(); if( resolution == Resolution.NAME ) { - String name = field.getName(); - return state.getValueByName( name ); + return state.getValueByName( field.getName() ); } - return state.getValueByType( type ); + return state.getValueByType( field.getType() ); } private Resolution getResolution( Field field ) { @@ -146,9 +144,23 @@ private Resolution getDeclaredResolution( Field field ) { return ( (ExpectedScenarioState) annotation ).resolution(); } } + throw new IllegalArgumentException( "Field " + field + " has no valid annotation" ); } + private boolean isRequired( Field field ) { + for( Annotation annotation : field.getAnnotations() ) { + if( annotation instanceof ScenarioState ) { + return ( (ScenarioState) annotation ).required(); + } + if( annotation instanceof ExpectedScenarioState ) { + return ( (ExpectedScenarioState) annotation ).required(); + } + } + + return false; + } + private boolean typeIsTooGeneric( Class type ) { return type.isPrimitive() || type.getName().startsWith( "java.lang" ) diff --git a/jgiven-junit/src/test/java/com/tngtech/jgiven/junit/ScenarioExecutionTest.java b/jgiven-junit/src/test/java/com/tngtech/jgiven/junit/ScenarioExecutionTest.java index 26bd8d0ec29..f7c2c956d4b 100644 --- a/jgiven-junit/src/test/java/com/tngtech/jgiven/junit/ScenarioExecutionTest.java +++ b/jgiven-junit/src/test/java/com/tngtech/jgiven/junit/ScenarioExecutionTest.java @@ -352,4 +352,17 @@ public void abstract_steps_should_appear_in_the_report_model() throws Throwable } + static class StageWithMissingState { + @ScenarioState( required = true ) + Boolean willNotBeProvided; + + public void something() {} + } + + @Test( expected = RuntimeException.class ) + public void required_states_must_be_present() throws Throwable { + StageWithMissingState stage = addStage( StageWithMissingState.class ); + stage.something(); + } + }