JBehave
  1. JBehave
  2. JBEHAVE-748

When @Named parameter matches name in Example table, it might be injected for steps that do not reference it

    Details

    • Type: Bug Bug
    • Status: Open Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 3.5.4
    • Fix Version/s: None
    • Component/s: Core
    • Labels:
      None
    • Environment:
      Windows 7, Java 6
    • Number of attachments :
      0

      Description

      When a step with @Named parameters is used in a scenario that uses an Example table for SOME of its steps, but for this specific step is given some explicit value, then IF the parameter name is not fully surrounded with whitespace AND it matches a name from the Examples table, then the given value is ignored. Instead, the value from the Examples table is injected.

      If the parameter name is unrelated to anything in the Examples table, then all is fine, even when the parameter is not fully surrounded with whitespace.

      (This is slightly related to http://jira.codehaus.org/browse/JBEHAVE-646)

      For example, all fine:

      @Given("I have <a> and <b>")
      public void givenAAndB(@Named("a") String myA, @Named("b") String myB) {
          assertThat(myA).isEqualTo("this");
          assertThat(myB).isEqualTo("that");
      }
      
      @When("I do <a>")
      public void whenIDoA(@Named("a") String myA) {
          assertThat(myA).isEqualTo("this");
      }
      
      @Then("I see <b>")
      public void thenISeeB(@Named("b") String myB) {
          assertThat(myB).isEqualTo("that");
      }
      
      // $x not surrounded by all whitespace, but "x" NOT known in Examples table: all fine
      @When("I did '$x'")
      public void whenIDidX(@Named("x") String myX) {
          assertThat(myX).isEqualTo("foo");
      }
      

      ...but wrong:

      // $b not surrounded by all whitespace, and "b" also known in Examples table
      @Then("I saw '$b'")
      public void thenISawB(@Named("b") String myB) {
          // Will fail: is assigned "that" from Examples table instead
          assertThat(myB).isEqualTo("bar");
      }
      

      ...when used with:

      Given I have <a> and <b>
      When I did 'foo'
      And I do <a>
      Then I see <b>
      And I saw 'bar'
      
      
      Examples:
      
      |   a|   b|
      |this|that|
      

        Activity

        Hide
        Arjan van Bentem added a comment - - edited

        Based on other unit tests from org.jbehave.core.steps.StepCandidateBehaviour, the following fails in 3.5.4:

        @Test
        public void shouldNotCreateStepFromTableValuesViaAnnotations() throws Exception {
            AnnotationNamedParameterSteps steps = new AnnotationNamedParameterSteps();
            // Parameter values from Examples: table should NOT be used in this test.
            // When removing the next two lines, or when using a different name for "ith",
            // then all is fine:
            namedParameters.put("ith", "top");
            namedParameters.put("nth", "penthouse");
            // Even with the above namedParameters as provided, then the following pattern
            // works fine if $ith is fully surrounded with whitespace, like:
            //   String patternAsString = "I live on the $ith but some call it the $nth";
            // ...but not when a comma follows the parameter name:
            String patternAsString = "I live on the $ith, but some call it the $nth";
            Method method = stepMethodFor("methodWithNamedParametersInNaturalOrder", AnnotationNamedParameterSteps.class);
            StepCandidate candidate = candidateWith(patternAsString, WHEN, method, steps);
            candidate.createMatchedStep("When I live on the first, but some call it the ground", namedParameters)
                    .perform(null);
            // Will fail in 3.5.4:
            // java.lang.AssertionError: Expected: "first" got: "top"
            assertThat(steps.ith, equalTo("first"));
            assertThat(steps.nth, equalTo("ground"));
        }
        
        Show
        Arjan van Bentem added a comment - - edited Based on other unit tests from org.jbehave.core.steps.StepCandidateBehaviour , the following fails in 3.5.4: @Test public void shouldNotCreateStepFromTableValuesViaAnnotations() throws Exception { AnnotationNamedParameterSteps steps = new AnnotationNamedParameterSteps(); // Parameter values from Examples: table should NOT be used in this test. // When removing the next two lines, or when using a different name for "ith" , // then all is fine: namedParameters.put( "ith" , "top" ); namedParameters.put( "nth" , "penthouse" ); // Even with the above namedParameters as provided, then the following pattern // works fine if $ith is fully surrounded with whitespace, like: // String patternAsString = "I live on the $ith but some call it the $nth" ; // ...but not when a comma follows the parameter name: String patternAsString = "I live on the $ith, but some call it the $nth" ; Method method = stepMethodFor( "methodWithNamedParametersInNaturalOrder" , AnnotationNamedParameterSteps.class); StepCandidate candidate = candidateWith(patternAsString, WHEN, method, steps); candidate.createMatchedStep( "When I live on the first, but some call it the ground" , namedParameters) .perform( null ); // Will fail in 3.5.4: // java.lang.AssertionError: Expected: "first" got: "top" assertThat(steps.ith, equalTo( "first" )); assertThat(steps.nth, equalTo( "ground" )); }
        Hide
        Arjan van Bentem added a comment - - edited

        For 3.6-SNAPSHOT, things seem to be worse. Even when fully surrounded with whitespace, it seems the values from any Examples: table are always preferred, if a parameter name happens to match a name from such Examples: table.

        For 3.6-SNAPSHOT:

        @Test
        public void shouldNotCreateStepFromTableValuesViaAnnotations() throws Exception {
            StoryReporter reporter = mock(StoryReporter.class);
            AnnotationNamedParameterSteps steps = new AnnotationNamedParameterSteps();
            // Parameter values from an Examples table should NOT be used when the step
            // does not refer to <ith> and <nth> but gives specific values instead. But
            // in 3.5.4 and 3.6 SNAPSHOT the specific values are ignored if they happen
            // to use the same name as used in the Examples table.
            // When removing the next two lines, or when using a different name for 
            // BOTH "ith" and "nth", then all is fine. (In 3.5.4, only "ith" needs to
            // be removed or renamed; in 3.6-SNAPSHOT both.)
            namedParameters.put("ith", "top");
            namedParameters.put("nth", "penthouse");
            // In 3.5.4, even with the above namedParameters as provided, the following
            // pattern only failed when some non-whitespace followed the parameter, like
            // when adding a comma after "$ith":
            //   String patternAsString = "I live on the $ith, but some call it the $nth";
            // In 3.6-SNAPSHOT, this fails without that comma too, and also for $nth:
            String patternAsString = "I live on the $ith floor but some call it the $nth";
            Method method = stepMethodFor("methodWithNamedParametersInNaturalOrder", AnnotationNamedParameterSteps.class);
            StepCandidate candidate = candidateWith(patternAsString, WHEN, method, steps);
            StepResult result =candidate.createMatchedStep("When I live on the first floor but some call it the ground", namedParameters)
                    .perform(null);
            // Will fail in both 3.5.4 and in 3.6-SNAPSHOT:
            // java.lang.AssertionError: Expected: "first" got: "top"
            assertThat(steps.ith, equalTo("first"));
            // Will fail in 3.6-SNAPSHOT:
            // java.lang.AssertionError: Expected: "ground" got: "penthouse"
            assertThat(steps.nth, equalTo("ground"));
            result.describeTo(reporter);
            verify(reporter).successful(
                    "When I live on the " + PARAMETER_VALUE_START + "first" + PARAMETER_VALUE_END + " floor but some call it the " + PARAMETER_VALUE_START + "ground" + PARAMETER_VALUE_END );
        }

        In 3.5.4, org.jbehave.core.parsers.RegexPrefixCapturingPatternParser#findParametersToReplace finds ith, (including the comma) and nth as the parameter names. In 3.6 SNAPSHOT, org.jbehave.core.parsers.RegexPrefixCapturingPatternParser.Parameter has changed, and (correctly) finds ith and nth. But still the values from the Examples: table overwrite both.

        Show
        Arjan van Bentem added a comment - - edited For 3.6-SNAPSHOT, things seem to be worse. Even when fully surrounded with whitespace, it seems the values from any Examples: table are always preferred, if a parameter name happens to match a name from such Examples: table. For 3.6-SNAPSHOT: @Test public void shouldNotCreateStepFromTableValuesViaAnnotations() throws Exception { StoryReporter reporter = mock(StoryReporter.class); AnnotationNamedParameterSteps steps = new AnnotationNamedParameterSteps(); // Parameter values from an Examples table should NOT be used when the step // does not refer to <ith> and <nth> but gives specific values instead. But // in 3.5.4 and 3.6 SNAPSHOT the specific values are ignored if they happen // to use the same name as used in the Examples table. // When removing the next two lines, or when using a different name for // BOTH "ith" and "nth" , then all is fine. (In 3.5.4, only "ith" needs to // be removed or renamed; in 3.6-SNAPSHOT both.) namedParameters.put( "ith" , "top" ); namedParameters.put( "nth" , "penthouse" ); // In 3.5.4, even with the above namedParameters as provided, the following // pattern only failed when some non-whitespace followed the parameter, like // when adding a comma after "$ith" : // String patternAsString = "I live on the $ith, but some call it the $nth" ; // In 3.6-SNAPSHOT, this fails without that comma too, and also for $nth: String patternAsString = "I live on the $ith floor but some call it the $nth" ; Method method = stepMethodFor( "methodWithNamedParametersInNaturalOrder" , AnnotationNamedParameterSteps.class); StepCandidate candidate = candidateWith(patternAsString, WHEN, method, steps); StepResult result =candidate.createMatchedStep( "When I live on the first floor but some call it the ground" , namedParameters) .perform( null ); // Will fail in both 3.5.4 and in 3.6-SNAPSHOT: // java.lang.AssertionError: Expected: "first" got: "top" assertThat(steps.ith, equalTo( "first" )); // Will fail in 3.6-SNAPSHOT: // java.lang.AssertionError: Expected: "ground" got: "penthouse" assertThat(steps.nth, equalTo( "ground" )); result.describeTo(reporter); verify(reporter).successful( "When I live on the " + PARAMETER_VALUE_START + "first" + PARAMETER_VALUE_END + " floor but some call it the " + PARAMETER_VALUE_START + "ground" + PARAMETER_VALUE_END ); } In 3.5.4, org.jbehave.core.parsers.RegexPrefixCapturingPatternParser#findParametersToReplace finds ith, (including the comma) and nth as the parameter names. In 3.6 SNAPSHOT, org.jbehave.core.parsers.RegexPrefixCapturingPatternParser.Parameter has changed, and (correctly) finds ith and nth . But still the values from the Examples: table overwrite both.
        Hide
        Arjan van Bentem added a comment - - edited

        Beware that the output on the screen might actually differ from the real parameter values. Like:

        Then I see <b>
        And I saw 'bar'
        

        ...will, while executing, be shown as:

        Then I see that
        And I saw 'bar'
        

        ...while in fact the last step will not use bar but that.

        Show
        Arjan van Bentem added a comment - - edited Beware that the output on the screen might actually differ from the real parameter values. Like: Then I see <b> And I saw 'bar' ...will, while executing, be shown as: Then I see that And I saw 'bar' ...while in fact the last step will not use bar but that .
        Hide
        Mauro Talevi added a comment -

        Hi Arjan,

        at present, the table values (in fact any named parameters) will override the step matched values. We could make this behaviour configurable.

        The workaround is to use different names for the table parameters or not use matched values.

        Show
        Mauro Talevi added a comment - Hi Arjan, at present, the table values (in fact any named parameters) will override the step matched values. We could make this behaviour configurable. The workaround is to use different names for the table parameters or not use matched values.
        Hide
        Arjan van Bentem added a comment -

        @Mauro,

        If this could be configurable, then I wonder in what use case would one enable it? Like in what use case would one like/expect/need I saw 'bar' to be executed as if one typed I saw <b>?

        Oh, maybe the same mechanism is used to have MORE parameters available in the Java step handlers than those that are actually defined in the textual step? Like I could use both <a> and <b> in the Java code while the @Given/@When/@Then doesn't even refer to those. That might indeed be something folks expect and use.

        Show
        Arjan van Bentem added a comment - @Mauro, If this could be configurable, then I wonder in what use case would one enable it? Like in what use case would one like/expect/need I saw 'bar' to be executed as if one typed I saw <b> ? Oh, maybe the same mechanism is used to have MORE parameters available in the Java step handlers than those that are actually defined in the textual step? Like I could use both <a> and <b> in the Java code while the @Given/@When/@Then doesn't even refer to those. That might indeed be something folks expect and use.
        Hide
        Mauro Talevi added a comment -

        Yes, that is my question as well.

        The principle underlying the current behaviour is the "out-in", i.e. any named parameter specified in the table will override a matched parameter. You are free to use multiple parameters for different scopes, e.g. matched parameters for normal steps and named parameters for parametrised scenarios (i.e. using examples tables).

        There is a fundamental difference between matched parameters (i.e. using the $name notation) and any other convention, e.g. <a> and <b>. The latter is only used to match the step to the method but then the parameters are passed by name, using the @Named annotation.

        As of 3.6, there is a new behaviour whereby the parametrisation can be done also by delimited named convention without @Named annotations (JBEHAVE-720).

        So, I'm not sure where we stand with this issue. Is there an enhancement that you'd like to propose? A clarification of the docs?

        Show
        Mauro Talevi added a comment - Yes, that is my question as well. The principle underlying the current behaviour is the "out-in", i.e. any named parameter specified in the table will override a matched parameter. You are free to use multiple parameters for different scopes, e.g. matched parameters for normal steps and named parameters for parametrised scenarios (i.e. using examples tables). There is a fundamental difference between matched parameters (i.e. using the $name notation) and any other convention, e.g. <a> and <b>. The latter is only used to match the step to the method but then the parameters are passed by name, using the @Named annotation. As of 3.6, there is a new behaviour whereby the parametrisation can be done also by delimited named convention without @Named annotations ( JBEHAVE-720 ). So, I'm not sure where we stand with this issue. Is there an enhancement that you'd like to propose? A clarification of the docs?
        Hide
        Olmo Rigolo added a comment - - edited

        Hi all,

        I use this bug as a workaround for this problem: http://jira.codehaus.org/browse/JBEHAVE-232

        This is a combination of example-data and variabes:

        Scenario: Combination of variable and example-data
        When user sets 'usernameField' to <value>
        When user sets 'passwordField' to <value>
        
        Examples:
        value
        username
        password
        
        @When("user sets '$fieldname' to <value>")
        public void whenUserSetsUsernameFieldTovalue(@Named("fieldname") final String fieldname, @Named("value") final String value) { 
           System.out.println(fieldname + value); 
        }
        
        Show
        Olmo Rigolo added a comment - - edited Hi all, I use this bug as a workaround for this problem: http://jira.codehaus.org/browse/JBEHAVE-232 This is a combination of example-data and variabes: Scenario: Combination of variable and example-data When user sets 'usernameField' to <value> When user sets 'passwordField' to <value> Examples: value username password @When( "user sets '$fieldname' to <value>" ) public void whenUserSetsUsernameFieldTovalue(@Named( "fieldname" ) final String fieldname, @Named( "value" ) final String value) { System .out.println(fieldname + value); }

          People

          • Assignee:
            Unassigned
            Reporter:
            Arjan van Bentem
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated: