Christian Hujer
Christian Hujer

Reputation: 17945

Use placeholders in feature files

I would like to use placeholders in a feature file, like this:

Feature: Talk to two servers
  Scenario: Forward data from Server A to Server B
    Given MongoDb collection "${db1}/foo" contains the following record:
      """
      {"key": "value"}
      """
    When I send GET "${server1}/data"
    When I forward the respone to PUT "${server2}/data"
    Then MongoDB collection "${db2}/bar" MUST contain the following record:
      """
      {"key": "value"}
      """

The values of ${server1} etc. would depend on the environment in which the test is to be executed (dev, uat, stage, or prod). Therefore, Scenario Outlines are not applicable in this situation.

Is there any standard way of doing this? Ideally there would be something which maintains a Map<String, String> that can be filled in a @Before or so, and runs automatically between Cucumber and the Step Definition so that inside the step definitions no code is needed.

Given the following step definitions

public class MyStepdefs {
    @When("^I send GET "(.*)"$)
    public void performGET(final String url) {
      // …
    }
}

And an appropriate setup, when performGET() is called, the placeholder ${server1} in String uri should already be replaced with a lookup of a value in a Map.

Is there a standard way or feature of Cucumber-Java of doing this? I do not mind if this involves dependency injection. If dependency injection is involved, I would prefer Spring, as Spring is already in use for other reasons in my use case.

Upvotes: 2

Views: 3328

Answers (2)

user861594
user861594

Reputation: 5908

The feature you are looking for is supported in gherkin with qaf. It supports to use properties defined in properties file using ${prop.key}. In addition it offers strong resource configuration features to work with different environments. It also supports web-services

Upvotes: 1

M.P. Korstanje
M.P. Korstanje

Reputation: 12039

The simple answer is that you can't.

The solution to your problem is to remove the incidental details from your scenario all together and access specific server information in the step defintions.

  • The server and database obviously belong together so lets describe them as a single entity, a service.
  • The details about the rest calls doesn't really help to convey what you're actually doing. Features don't describe implementation details, they describe behavior.
  • Testing if records have been inserted into the database is another bad practice and again doesn't describe behavior. You should be able to replace that by an other API call that fetches the data or some other process that proves the other server has received the information. If there are no such means to extract the data available you should create them. If they can't be created you can wonder if the information even needs to be stored (your service would then appear to have the same properties as a black hole :) ).

I would resolve this all by rewriting the story such that:

Feature: Talk to two services
  Scenario: Forward foobar data from Service A  to Service B
    Given "Service A" has key-value information
    When I forward the foobar data from "Service A" to "Service B"
    Then "Service B" has received the key-value information

Now that we have two entities Service A and Service B you can create a ServiceInformationService to look up information about Service A and B. You can inject this ServiceInformationService into your step definitions.

So when ever you need some information about Service A, you do

Service a = serviceInformationService.lookup("A");
String apiHost = a.getApiHost():  
String dbHost = a.getDatabaseHOst():  

In the implementation of the Service you look up the property for that service System.getProperty(serviceName + "_" + apiHostKey) and you make sure that your CI sets A_APIHOST and A_DBHOST, B_APIHOST, B_DBHOST, ect.

You can put the name of the collections in a property file that you look up in a similar way as you'd look up the system properties. Though I would avoid direct interaction with the DB if possible.

Upvotes: 4

Related Questions