JBehave
  1. JBehave
  2. JBEHAVE-720

Allow parametrisation of scenarios by delimited names

    Details

    • Type: Improvement Improvement
    • Status: Resolved Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 3.5.4
    • Fix Version/s: 3.6
    • Component/s: Core
    • Labels:
      None
    • Testcase included:
      yes
    • Number of attachments :
      1

      Description

      I'm working on a simplification of the current parameterized scenario solution. With this I want to:

      • avoid the need of defining two different patterns for steps, one for normal scenarios, and another for parameterized scenarios.
      • be able to use column names in Examples tables that differ from the parameter names that were specified in the step annotation
      • avoid having to annotate fields with @Named in parameterized step methods

      Take the following steps and scenario, for example:

      ParameterizedStory.java
      public class ParameterizedStory extends JUnitStory {
      
        public static class ParamsSteps {
          
          private String user;    
          private Set<String> products; // null means no cart...
      
          @BeforeScenario
          public void init() {
            user = null;
            products = null;
          }
          
          @Given("$user is logged in")
          public void loggedIn(String user) {
            this.user = user;
          }
          
          @Given("$customer has a cart")
          public void aCustomerHasACart(String customer) {
            assertThat(user, notNullValue());
            assertThat(customer, equalTo(user));
            if (products == null) products = new TreeSet<String>();
          }
           
          @When("a $product is added to the cart")
          public void aProductIsAddedToCart(String product) {
            assertThat(products, notNullValue());
            products.add(product);
          }
          
          @Then("cart contains $product")
          public void cartContains(String product) {
            assertThat(products, notNullValue());
            assertTrue(products.contains(product));
          }
        }
      
        public ParameterizedStory() {
          // Making sure this doesn't output to the build while it's running
          useConfiguration(new MostUsefulConfiguration()
            .useStoryReporterBuilder(new StoryReporterBuilder()
            .withFormats(Format.CONSOLE)
            .withFailureTrace(true)
            .withFailureTraceCompression(false))
            .usePendingStepStrategy(new FailingUponPendingStep())
            .useFailureStrategy(new RethrowingFailure()));
        }
        
        @Override
        public List<CandidateSteps> candidateSteps() {
          return new InstanceStepsFactory(configuration(), new ParamsSteps()).createCandidateSteps(); 
        }
      }
      
      parameterized_story.story
      Scenario: Use flexible parameters with examples table
      
      Given <client> is logged in
      And <client> has a cart
      When a <item> is added to the cart
      Then cart contains <item>
      
      Examples:
      |client|item|
      |Rui|chocolate|
      |Figueira|car|
      

      The "Given $user is logged in" step pattern will match "Given <client> is logged in", and user parameter will be set to client column values.
      The main idea is that <client>, instead of represent a named parameter, represents a placeholder, and that placeholder should be replaced with whether value exists for it in the examples table. Then, after replacing the placeholder with the corresponding value, it will then match with the given step pattern, and $user will be set to the correct value.

      I have a working version available at https://github.com/ruifigueira/jbehave-core/commit/a4107a3ac899c4b952746781f785cba9a97c659c, that can be used to test the scenario above.

        Activity

        Hide
        Rui Figueira added a comment -

        I forgot to mention two other advantages of this simplification:

        • it is possible to have steps with different parameter names that will use the same column values. In the example scenario, both "Given <client> is logged in" and "And <client> has a cart" will "share" the same column value (client), even if one of the steps parameter is named $user and the other is $customer.
        • it is possible to have two different steps with the same parameter name, and then when using both steps in the same parameterized scenario pass them different values
        Show
        Rui Figueira added a comment - I forgot to mention two other advantages of this simplification: it is possible to have steps with different parameter names that will use the same column values. In the example scenario, both "Given <client> is logged in" and "And <client> has a cart" will "share" the same column value (client), even if one of the steps parameter is named $user and the other is $customer. it is possible to have two different steps with the same parameter name, and then when using both steps in the same parameterized scenario pass them different values
        Hide
        Mauro Talevi added a comment -

        Hi Rui,

        very interesting submission. I'm trying to understand what's really changed under the hood. AFAICS, the changes are mostly cosmetic, except for the crucial change on line 105 of the StepCreator.

        for (int i = 0; i < names.length; i++) {
          String name = names[i].getName();
          if (name == null) name = stepMatcher.parameterNames()[i];
          matchedParameters.put(name, values[i]);
        }
        

        That said, if you try to apply this change alone, your example does not work without using @Named annotations. Am I missing something?

        Show
        Mauro Talevi added a comment - Hi Rui, very interesting submission. I'm trying to understand what's really changed under the hood. AFAICS, the changes are mostly cosmetic, except for the crucial change on line 105 of the StepCreator. for ( int i = 0; i < names.length; i++) { String name = names[i].getName(); if (name == null ) name = stepMatcher.parameterNames()[i]; matchedParameters.put(name, values[i]); } That said, if you try to apply this change alone, your example does not work without using @Named annotations. Am I missing something?
        Rui Figueira made changes -
        Field Original Value New Value
        Attachment StepCreator.java [ 58919 ]
        Hide
        Rui Figueira added a comment - - edited

        Hi Mauro,

        I forgot to include a previous commit ( https://github.com/ruifigueira/jbehave-core/commit/1f4491c608d336a5552c457248a6e6d3854d58f1 ) that has the code change to avoid using @Named annotations (line 242):

        if (parameter == null) {
          stepMonitor.usingNaturalOrderForParameter(position);
          parameter = matchedParameter(position);
          String placeholderName = getPlaceholderName(parameter);
        	
          if(placeholderName != null && isTableName(namedParameters, placeholderName)) {
            parameter = namedParameter(namedParameters, placeholderName);
          }
        }
        

        I attached the StepsCreator class (from the head of the current master branch) with the changes needed so that my scenario test will work (with @Named annotations omitted).

        Regards

        Show
        Rui Figueira added a comment - - edited Hi Mauro, I forgot to include a previous commit ( https://github.com/ruifigueira/jbehave-core/commit/1f4491c608d336a5552c457248a6e6d3854d58f1 ) that has the code change to avoid using @Named annotations (line 242): if (parameter == null ) { stepMonitor.usingNaturalOrderForParameter(position); parameter = matchedParameter(position); String placeholderName = getPlaceholderName(parameter); if (placeholderName != null && isTableName(namedParameters, placeholderName)) { parameter = namedParameter(namedParameters, placeholderName); } } I attached the StepsCreator class (from the head of the current master branch) with the changes needed so that my scenario test will work (with @Named annotations omitted). Regards
        Mauro Talevi made changes -
        Summary Parametrised scenarios can be simplified Allow parametrisation of scenarios by delimited names
        Assignee Mauro Talevi [ maurotalevi ]
        Fix Version/s 3.6 [ 17721 ]
        Mauro Talevi made changes -
        Status Open [ 1 ] In Progress [ 3 ]
        Hide
        Mauro Talevi added a comment -

        Ah, that makes more sense I've applied the patch (with minor renames and modifications).

        Please merge with latest master and verify it works for you (your version was not in sync with latest master)

        I've added parametrisation_by_delimited_names.story to trader example to verify behaviour.

        Thanks

        Show
        Mauro Talevi added a comment - Ah, that makes more sense I've applied the patch (with minor renames and modifications). Please merge with latest master and verify it works for you (your version was not in sync with latest master) I've added parametrisation_by_delimited_names.story to trader example to verify behaviour. Thanks
        Hide
        Mauro Talevi added a comment -

        Behaviour made non-default (to ensure backward compat) and configurable via ParameterControls.

        Show
        Mauro Talevi added a comment - Behaviour made non-default (to ensure backward compat) and configurable via ParameterControls.
        Hide
        Rui Figueira added a comment -

        I just merged with the latest master, configured the ParameterControls properly, and everything keeps working just fine

        Show
        Rui Figueira added a comment - I just merged with the latest master, configured the ParameterControls properly, and everything keeps working just fine
        Mauro Talevi made changes -
        Status In Progress [ 3 ] Resolved [ 5 ]
        Resolution Fixed [ 1 ]

          People

          • Assignee:
            Mauro Talevi
            Reporter:
            Rui Figueira
          • Votes:
            2 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: