Hot questions for Using Cucumber in testing

Question:

Recently there was a discussion in my team about how to properly test a component of our system where the output is stored in a database. We use DDD to create our system so the component ultimately talks to a repository that has different stores implemented to talk to a MongoDB. As testing framework we use Cucumber and the database we use for testing is an in-memory version of mongo.

Up until now, all our scenarios had a command as input and the output was an event so our assertions were done on the event. But now we have a scenario where the event is processed and the result is stored in a database. The result can be retrieved using a rest call after that happens.

The discussion was about the way to test these two last scenarios. For some, the correct way is to check the in-memory database after the event is processed because that's the output of the system. The ultimate part of the system are the stores and they have to be tested as well as part of the scenario. Testing what the in-memory database contains is the right way as the stores are still using the same production ready logic to write the output. For convenience, we would use the repositories to retrieve this data as is easier this way, even when we need to use something not related to the scenario at hand.

On the other hand, for some people we shouldn't be checking the database as that's another component which we shouldn't be accessing for the test. Instead, because in this case the rest call is just retrieving the data, we should use the rest call as part of the test to verify the output. This way, our scenario would include this 2 parts, the storing and the retrieving instead of splitting the tests.

Is there any correct answer to this? Are we missing any point here? Thanks.


Answer:

I'd say verifying with a REST call is the correct way to do it here. Otherwise it wouldn't really be blackbox testing, and your test will depend on internal implementation details (your database structure). You usually want to see what effect your application has on the "outside world", and your database is not part of this IMO.

This is all assuming the tests you are creating are intended to be blackbox tests. If it's an integration test (~grey box I guess?) then IMO checking the database using the repository is probably a better idea.

If it's intended to be a unit test, the dependencies of your component should be mocked. You can then use the mocks to verify that your component called the repository correctly.

If I misunderstood something, do let me know. :)

Question:

I'm started work on test automation and at the moment I have a small problem.

I made the Gherkin Scenario:

Feature: Post Draft

  Scenario: Successful Login with Valid Credentials
    Given User go to Admin Page
    Then User enters UserName and Password

  Scenario Outline: Successful creation post draft
    Given User navigate to pages list
    Then User open page with ID <postsIds> for editing
    Then User navigate to Advertising tab
    Then User check custom ads code radio button
    And Insert custom advertising code
    Then User save post
    And See that custom ads code is appears

    Examples:
      | postsIds |
      | 61591    |
      | 62231    |
      | 61827    |
      | 63300    |
      | 62023    |
      | 62231    |

And When I trying to execute this scenario I'm got the error:

cucumber.runtime.CucumberException: Failed to create scenario runner
    ... 21 more

Have someone the same problem? I have no idea what the problem, because if I delete Outline keyword and Examples list, test is running...

I implemented all steps, and it's works without Outline, but I have a lot of values and I don't want to implement steps for each value, that why I need to use Scenario Outline

Please, help me to resolve this issue.


Answer:

I found the problem. I updated cucumber-junit package to latest version and it's haven't backward compatibility.

Here is Maven dependencies, that works:

<dependencies>
    <dependency>
        <groupId>info.cukes</groupId>
        <artifactId>cucumber-picocontainer</artifactId>
        <version>1.1.8</version>
    </dependency>
    <dependency>
        <groupId>info.cukes</groupId>
        <artifactId>cucumber-junit</artifactId>
        <version>1.1.8</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
    </dependency>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-server</artifactId>
        <version>2.42.2</version>
    </dependency>
</dependencies>

GHERKIN: SCENARIO OUTLINES

Also I have an article with Cucumber testing guide

Question:

I have a stateless EJB that uses @PersistenceContext with a EntityManager, I'm writing a cucumber step definitions class that uses this Service to perform steps in testing finding users based upon supplied criteria.

So for example

@Stateless
public class UserService {

    @PersistenceContext
    private EntityManager em;

    public void add(String userName) {
        User user = new User(userName);
        em.persist(user);
    }    

    public List<User> findByName(String userName) {
        return em.createQuery("Select u from User as u WHERE u.name LIKE :userName").setParameter("userName", userName).getResultList();
    }

}

And a feature file that looks something like

Feature: Search

    Given a user with the name 'Jason Statham'
        And another user with the name 'Bill Gates'
        And another user with the name 'Larry Page'
    When the customer searches for a user with the name 'Jason'
    Then 1 users should have been found
        And User 1 should have a name of 'Jason Statham'

And a steps definition class

 public class SearchStepsDefinitions {

   private List<User> userList = new ArrayList<>();
   private UserService userService = new UserService();

   @Given(value = ".+user with the name '(.+)'$")
   public void a_user_with_the_name(final String userName) {
       userService.add(userName);
   }

   @When(value = "^the customer searches for a user with the name '(.+)'$")
   public void the_customer_searches_for_a_user_with_the_name(final String name) {
       userList = userService.findByName(name); 
   }

   @Then(value = "(\\d+) users should have been found$")
   public void users_should_have_been_found(final int userCount) {
       assertThat(userList.size(), equalTo(userCount));
   }

   @Then(value = "User (\\d+) should have a name of '(.+)'$")
   public void should_have_a_name_of(final int position, final String name) {
       assertThat(userList.get(position - 1).getName(), equalTo(name)); 
   }

}

Now I understand that as the Service is an EJB the EntityManager is injected via the @PersistenceContext.

My question is in the steps definition how should I be dealing with this dependency? Should I be mocking it and injecting this mock into the UserService, or should the UserService have a setter for the EntityManager and use a EntityManagerFactory to create one in the SearchStepsDefinitions?

So in other words

@Stateless
public class UserService {

    @PersistenceContext
    private EntityManager em;

    public void add(String userName) {
        User user = new User(userName);
        em.persist(user);
    }    

    public List<User> findByName(String userName) {
        return em.createQuery("Select u from User as u WHERE u.name LIKE :userName").setParameter("userName", userName).getResultList();
    }

    public void setEm(EntityManager em) {
        this.em = em;
    }

}

Then the steps definition would either be this

public class SearchStepsDefinitions {

   private List<User> userList = new ArrayList<>();

   @Mock
   private EntityManager em;       

   @Inject
   @InjectMocks
   private UserService userService;

   @Given(value = ".+user with the name '(.+)'$")
   public void a_user_with_the_name(final String userName) {
       userService.add(userName);
   }

   @When(value = "^the customer searches for a user with the name '(.+)'$")
   public void the_customer_searches_for_a_user_with_the_name(final String name) {
       userList = userService.findByName(name); 
   }

   @Then(value = "(\\d+) users should have been found$")
   public void users_should_have_been_found(final int userCount) {
       assertThat(userList.size(), equalTo(userCount));
   }

   @Then(value = "User (\\d+) should have a name of '(.+)'$")
   public void should_have_a_name_of(final int position, final String name) {
       assertThat(userList.get(position - 1).getName(), equalTo(name)); 
   }

}

Or this

public class SearchStepsDefinitions {

   private List<User> userList = new ArrayList<>();

   private UserService userService = new UserService();

   @Before
   public void setup() {
       userService.setEm(Persistence.createEntityManagerFactory("punit").createEntityManager());
   }

   @Given(value = ".+user with the name '(.+)'$")
   public void a_user_with_the_name(final String userName) {
       userService.add(userName);
   }

   @When(value = "^the customer searches for a user with the name '(.+)'$")
   public void the_customer_searches_for_a_user_with_the_name(final String name) {
       userList = userService.findByName(name); 
   }

   @Then(value = "(\\d+) users should have been found$")
   public void users_should_have_been_found(final int userCount) {
       assertThat(userList.size(), equalTo(userCount));
   }

   @Then(value = "User (\\d+) should have a name of '(.+)'$")
   public void should_have_a_name_of(final int position, final String name) {
       assertThat(userList.get(position - 1).getName(), equalTo(name)); 
   }

}

Essentially I'm trying to do the same as this example but I'm not using Spring

Or perhaps another option would be to not have the service as an EJB and @Inject the EntityManager into it

public class UserService {

    @Inject
    private EntityManager em;

    public void add(String userName) {
        User user = new User(userName);
        em.persist(user);
    }    

    public List<User> findByName(String userName) {
        return em.createQuery("Select u from User as u WHERE u.name LIKE :userName").setParameter("userName", userName).getResultList();
    }

}

And then the steps would look like

 public class SearchStepsDefinitions {

   private List<User> userList = new ArrayList<>();

   @Inject
   private UserService userService;

   @Given(value = ".+user with the name '(.+)'$")
   public void a_user_with_the_name(final String userName) {
       userService.add(userName);
   }

   @When(value = "^the customer searches for a user with the name '(.+)'$")
   public void the_customer_searches_for_a_user_with_the_name(final String name) {
       userList = userService.findByName(name); 
   }

   @Then(value = "(\\d+) users should have been found$")
   public void users_should_have_been_found(final int userCount) {
       assertThat(userList.size(), equalTo(userCount));
   }

   @Then(value = "User (\\d+) should have a name of '(.+)'$")
   public void should_have_a_name_of(final int position, final String name) {
       assertThat(userList.get(position - 1).getName(), equalTo(name)); 
   }

}

I'm not really sure of the pro's and con's of these approaches?


Answer:

After much digging I discovered I need to use an EJBContainer, then the Steps class now looks like this

 public class SearchStepsDefinitions {

   private Context context;
   private EJBContainer container;

   private List<User> userList = new ArrayList<>();

   private UserService userService;

   @cucumber.api.java.Before
   public void setup() {
       ejbContainer = EJBContainer.createEJBContainer();
       context = ejbContainer.getContext();

       userService = (UserService) context.lookup("java:global/classes/UserService");
   }

   @cucumber.api.java.After
   public void teardown() {
       ejbContainer.close();
   }

   @Given(value = ".+user with the name '(.+)'$")
   public void a_user_with_the_name(final String userName) {
       userService.add(userName);
   }

   @When(value = "^the customer searches for a user with the name '(.+)'$")
   public void the_customer_searches_for_a_user_with_the_name(final String name) {
       userList = userService.findByName(name); 
   }

   @Then(value = "(\\d+) users should have been found$")
   public void users_should_have_been_found(final int userCount) {
       assertThat(userList.size(), equalTo(userCount));
   }

   @Then(value = "User (\\d+) should have a name of '(.+)'$")
   public void should_have_a_name_of(final int position, final String name) {
       assertThat(userList.get(position - 1).getName(), equalTo(name)); 
   }

}

One additional thing that is required is a ejb container in the pom. I used glassfish, with this dependency.

<dependency>
    <groupId>org.glassfish.main.extras</groupId>
    <artifactId>glassfish-embedded-all</artifactId>
    <version>4.1</version>
</dependency>

Question:

I'm using cucumber and maven on eclipse and what I'm trying to do is run each test independently. For example I have a library system software that basically allows users to borrow books and do other stuff.

One of the conditions is that users can only borrow a max of two books so I wrote to make sure that the functionality works. This is my feature file:

Scenario: Borrow over max limit
Given "jim@help.ca" logs in to the library system
When "jim@help.ca" order his first book with ISBN "9781611687910"
And "jim@help.ca" orders another book with ISBN "9781442667181"
And "jim@help.ca" tries to order another book with ISBN "1234567890123"
Then jim will get the message that says "The User has reached his/her max number of books"

I wrote a corresponding step definition file and every worked out great. However, in the future I want to use the same username ("jim@help.ca") for borrowing books as though jim@help.ca has not yet borrowed any books. I want each test to be independent of each other.

Is there any way of doing this...maybe there's something I can put into my step definition classes such as a teardown method. I've looked into it but I couldn't fine any solid information about it. If there's a way please help me. Any help is greatly appreciated and I thank you in advance!


Answer:

Yes, you can do setups and teardowns before and after each scenario, but it's not in the step definition file. What you want to use are hooks.

Hooks run before or after a scenario and can run before/after every scenario or just the ones you and @tag to, for example:

@remove_borrowed_books
Scenario: Borrow over max limit

Unfortunately I have only used cucumber with ruby not java so I can't give you step-by-step instructions, but this should tell you what you need to know https://zsoltfabok.com/blog/2012/09/cucumber-jvm-hooks/

Question:

I'm building a little maven application but I'm having problem with the cucumber tests. Here's the error that appears:

java.lang.NoSuchMethodError: org.glassfish.hk2.utilities.general.GeneralUtilities.getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    at org.jvnet.hk2.internal.ServiceLocatorImpl.<clinit>(ServiceLocatorImpl.java:122)
    at org.jvnet.hk2.external.generator.ServiceLocatorGeneratorImpl.initialize(ServiceLocatorGeneratorImpl.java:66)
    at org.jvnet.hk2.external.generator.ServiceLocatorGeneratorImpl.create(ServiceLocatorGeneratorImpl.java:96)
    at org.glassfish.hk2.internal.ServiceLocatorFactoryImpl.internalCreate(ServiceLocatorFactoryImpl.java:312)
    at org.glassfish.hk2.internal.ServiceLocatorFactoryImpl.create(ServiceLocatorFactoryImpl.java:293)
    at org.glassfish.hk2.internal.ServiceLocatorFactoryImpl.create(ServiceLocatorFactoryImpl.java:157)
    at org.glassfish.hk2.utilities.ServiceLocatorUtilities.bind(ServiceLocatorUtilities.java:205)
    at org.glassfish.hk2.utilities.ServiceLocatorUtilities.bind(ServiceLocatorUtilities.java:220)
    at cucumber.runtime.java.hk2.impl.HK2Factory.start(HK2Factory.java:40)
    at cucumber.runtime.java.JavaBackend.buildWorld(JavaBackend.java:125)
    at cucumber.runtime.Runtime.buildBackendWorlds(Runtime.java:139)
    at cucumber.runtime.model.CucumberScenario.run(CucumberScenario.java:38)
    at cucumber.runtime.junit.ExecutionUnitRunner.run(ExecutionUnitRunner.java:91)
    at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:63)
    at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:18)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at cucumber.runtime.junit.FeatureRunner.run(FeatureRunner.java:70)
    at cucumber.api.junit.Cucumber.runChild(Cucumber.java:93)
    at cucumber.api.junit.Cucumber.runChild(Cucumber.java:37)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at cucumber.api.junit.Cucumber.run(Cucumber.java:98)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)

I'm pretty sure I've a problem with the dependencies, but I can't seem to find the problem, heres the result of running mvn dependency:tree

[INFO] com.sac.ergo.riskbusinessadmissions:risk-business-admissions:jar:1.0.0
[INFO] +- com.sac.jee.arq.spring.core:arq-spring-servicing-core:jar:5.4.4.4:compile
[INFO] |  +- com.sac.jee.arq.spring.core:arq-spring-servicing-logging:jar:5.4.4.3:compile
[INFO] |  |  +- com.sac.semaas:delta:jar:0.7.0:compile
[INFO] |  |  |  +- com.squareup.okhttp:okhttp:jar:2.5.0:compile
[INFO] |  |  |  |  \- com.squareup.okio:okio:jar:1.6.0:compile
[INFO] |  |  |  \- com.google.code.gson:gson:jar:2.7:compile
[INFO] |  |  +- log4j:log4j:jar:1.2.17:compile
[INFO] |  |  +- org.apache.cxf:cxf-core:jar:3.2.4:compile
[INFO] |  |  |  +- com.fasterxml.woodstox:woodstox-core:jar:5.0.3:compile
[INFO] |  |  |  |  \- org.codehaus.woodstox:stax2-api:jar:3.1.4:compile
[INFO] |  |  |  \- org.apache.ws.xmlschema:xmlschema-core:jar:2.2.3:compile
[INFO] |  |  +- org.mongodb:mongodb-driver:jar:3.4.0:compile
[INFO] |  |  |  +- org.mongodb:mongodb-driver-core:jar:3.4.0:compile
[INFO] |  |  |  \- org.mongodb:bson:jar:3.4.0:compile
[INFO] |  |  \- org.springframework:spring-web:jar:5.0.4.RELEASE:compile
[INFO] |  +- com.sac.jee.arq.spring.core:arq-spring-monitoring:jar:5.4.0.0:compile
[INFO] |  |  +- javax.servlet:javax.servlet-api:jar:3.1.0:compile
[INFO] |  |  +- javax.jms:jms:jar:1.1:compile
[INFO] |  |  +- org.apache.geronimo.specs:geronimo-commonj_1.1_spec:jar:1.0:compile
[INFO] |  |  +- javax.resource:connector-api:jar:1.5:compile
[INFO] |  |  \- com.rabbitmq:amqp-client:jar:3.3.5:compile
[INFO] |  +- com.sac.jee.arq.spring.core:arq-spring-servicing-fraud:jar:5.3.1.0:compile
[INFO] |  |  \- com.sac.jee.arq.spring.integraciones:securitydummy:jar:5.4.2.0:compile
[INFO] |  |     \- com.sac.jee.arq.spring.integraciones:mocking:jar:5.4.0.0:compile
[INFO] |  |        \- org.springframework:spring-expression:jar:5.0.4.RELEASE:compile
[INFO] |  +- com.sac.jee.arq.spring.core:arq-spring-connector-crypto:jar:5.4.0.2:compile
[INFO] |  |  +- com.sac.jee.arq.spring.core:arq-spring-connector-rest:jar:5.4.4.0:compile
[INFO] |  |  |  +- org.apache.cxf:cxf-rt-frontend-jaxws:jar:3.2.4:compile
[INFO] |  |  |  |  +- xml-resolver:xml-resolver:jar:1.2:compile
[INFO] |  |  |  |  +- org.ow2.asm:asm:jar:5.2:compile
[INFO] |  |  |  |  +- org.apache.cxf:cxf-rt-bindings-soap:jar:3.2.4:compile
[INFO] |  |  |  |  |  +- org.apache.cxf:cxf-rt-wsdl:jar:3.2.4:compile
[INFO] |  |  |  |  |  |  \- wsdl4j:wsdl4j:jar:1.6.3:compile
[INFO] |  |  |  |  |  \- org.apache.cxf:cxf-rt-databinding-jaxb:jar:3.2.4:compile
[INFO] |  |  |  |  +- org.apache.cxf:cxf-rt-bindings-xml:jar:3.2.4:compile
[INFO] |  |  |  |  +- org.apache.cxf:cxf-rt-frontend-simple:jar:3.2.4:compile
[INFO] |  |  |  |  \- org.apache.cxf:cxf-rt-ws-addr:jar:3.2.4:compile
[INFO] |  |  |  |     \- org.apache.cxf:cxf-rt-ws-policy:jar:3.2.4:compile
[INFO] |  |  |  |        \- org.apache.neethi:neethi:jar:3.1.1:compile
[INFO] |  |  |  +- org.apache.httpcomponents:httpmime:jar:4.5.5:compile
[INFO] |  |  |  +- com.google.api-client:google-api-client:jar:1.18.0-rc:compile
[INFO] |  |  |  |  \- com.google.oauth-client:google-oauth-client:jar:1.18.0-rc:compile
[INFO] |  |  |  +- com.google.http-client:google-http-client-jackson2:jar:1.18.0-rc:compile
[INFO] |  |  |  |  \- com.google.http-client:google-http-client:jar:1.18.0-rc:compile
[INFO] |  |  |  \- commons-httpclient:commons-httpclient:jar:3.1:compile
[INFO] |  |  \- com.sac.jee.arq.spring.integraciones:caasdummy:jar:5.4.0.0:compile
[INFO] |  +- com.sac.jee.arq.spring.core:arq-spring-connector-upsilon:jar:5.4.4.4:compile
[INFO] |  +- com.sac.jee.arq.spring.integraciones:sendsmsdummy:jar:5.0.4:compile
[INFO] |  +- com.sac.jee.arq.spring.core:arq-spring-backend-ps:jar:5.4.2.0:compile
[INFO] |  |  \- commons-collections:commons-collections:jar:3.2.1:compile
[INFO] |  +- com.sac.infrastructure.multichannel.api:multi-channel-infrastructure-api:jar:5.4.0.0:compile
[INFO] |  |  \- com.sac.jee.arq.spring.core:arq-spring-connector-semaas:jar:5.4.4.0:compile
[INFO] |  +- com.sac.jee.arq.spring.core:arq-spring-utils:jar:5.4.4.0:compile
[INFO] |  |  +- org.codehaus.jackson:jackson-mapper-asl:jar:1.8.0:compile
[INFO] |  |  \- org.codehaus.jackson:jackson-mapper-lgpl:jar:1.8.0:compile
[INFO] |  |     \- org.codehaus.jackson:jackson-core-lgpl:jar:1.8.0:compile
[INFO] |  +- com.sac.jee.arq.spring.cas.api:arq-spring-servicing-cas-api:jar:5.4.0.0:compile
[INFO] |  +- com.thoughtworks.xstream:xstream:jar:1.3.1:compile
[INFO] |  |  \- xpp3:xpp3_min:jar:1.1.4c:compile
[INFO] |  +- cglib:cglib-nodep:jar:2.2:compile
[INFO] |  +- org.springframework:spring-jdbc:jar:5.0.4.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-beans:jar:5.0.4.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-core:jar:5.0.4.RELEASE:compile
[INFO] |  |  |  \- org.springframework:spring-jcl:jar:5.0.4.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-tx:jar:5.0.4.RELEASE:compile
[INFO] |  +- org.springframework:spring-oxm:jar:5.0.4.RELEASE:compile
[INFO] |  +- org.springframework:spring-context-support:jar:5.0.4.RELEASE:compile
[INFO] |  +- com.googlecode.ehcache-spring-annotations:ehcache-spring-annotations:jar:1.2.0:compile
[INFO] |  |  +- aopalliance:aopalliance:jar:1.0:compile
[INFO] |  |  \- net.sf.ehcache:ehcache-core:jar:2.4.5:compile
[INFO] |  +- org.codehaus.jackson:jackson-mrbean:jar:1.8.0:compile
[INFO] |  +- org.codehaus.jackson:jackson-smile:jar:1.8.0:compile
[INFO] |  |  \- org.codehaus.jackson:jackson-core-asl:jar:1.8.0:compile
[INFO] |  +- org.codehaus.jackson:jackson-xc:jar:1.8.0:compile
[INFO] |  +- com.ibm:mq:jar:7.0.1.7:compile
[INFO] |  +- com.ibm:mqjms:jar:7.0.1.7:compile
[INFO] |  +- com.ibm.disthub2:dhbcore:jar:7.0.1.7:compile
[INFO] |  +- com.ibm.mq:jmqi:jar:7.0.1.7:compile
[INFO] |  +- com.ibm.mq:headers:jar:7.0.1.7:compile
[INFO] |  +- com.ibm.mq:commonservices:jar:7.0.1.7:compile
[INFO] |  +- com.ibm:connector:jar:1.3.0:compile
[INFO] |  +- org.apache.cxf:cxf-rt-features-clustering:jar:3.2.4:compile
[INFO] |  +- org.apache.cxf:cxf-rt-rs-service-description:jar:3.2.4:compile
[INFO] |  |  \- org.apache.cxf:cxf-rt-frontend-jaxrs:jar:3.2.4:compile
[INFO] |  +- org.apache.cxf:cxf-rt-rs-client:jar:3.2.4:compile
[INFO] |  |  \- org.apache.cxf:cxf-rt-transports-http:jar:3.2.4:compile
[INFO] |  +- commons-pool:commons-pool:jar:1.5.6:compile
[INFO] |  +- commons-dbcp:commons-dbcp:jar:1.3:compile
[INFO] |  +- commons-configuration:commons-configuration:jar:1.8:compile
[INFO] |  |  \- commons-lang:commons-lang:jar:2.6:compile
[INFO] |  +- com.hazelcast:hazelcast-all:jar:3.10.2:compile
[INFO] |  +- net.sf.flexjson:flexjson:jar:2.1:compile
[INFO] |  +- org.hibernate:hibernate-entitymanager:jar:5.2.16.Final:compile
[INFO] |  |  +- org.hibernate:hibernate-core:jar:5.2.16.Final:compile
[INFO] |  |  |  +- antlr:antlr:jar:2.7.7:compile
[INFO] |  |  |  \- org.jboss:jandex:jar:2.0.3.Final:compile
[INFO] |  |  +- org.hibernate.common:hibernate-commons-annotations:jar:5.0.1.Final:compile
[INFO] |  |  +- org.javassist:javassist:jar:3.22.0-GA:compile
[INFO] |  |  \- org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:jar:1.0.1.Final:compile
[INFO] |  +- com.wordnik:swagger-jaxrs_2.10:jar:1.3.0:compile
[INFO] |  |  +- org.scala-lang:scala-library:jar:2.10.0:compile
[INFO] |  |  \- com.wordnik:swagger-core_2.10:jar:1.3.0:compile
[INFO] |  |     +- com.fasterxml.jackson.module:jackson-module-scala_2.10:jar:2.1.5:compile
[INFO] |  |     |  \- org.scala-lang:scala-reflect:jar:2.10.0:compile
[INFO] |  |     +- com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.0.0:compile
[INFO] |  |     +- com.wordnik:swagger-annotations_2.10:jar:1.3.0:compile
[INFO] |  |     +- org.json4s:json4s-ext_2.10:jar:3.2.4:compile
[INFO] |  |     |  \- org.joda:joda-convert:jar:1.2:compile
[INFO] |  |     +- org.json4s:json4s-native_2.10:jar:3.2.4:compile
[INFO] |  |     |  \- org.json4s:json4s-core_2.10:jar:3.2.4:compile
[INFO] |  |     |     +- org.json4s:json4s-ast_2.10:jar:3.2.4:compile
[INFO] |  |     |     \- org.scala-lang:scalap:jar:2.10.0:compile
[INFO] |  |     |        \- org.scala-lang:scala-compiler:jar:2.10.0:compile
[INFO] |  |     \- org.json4s:json4s-jackson_2.10:jar:3.2.4:compile
[INFO] |  +- org.hibernate.validator:hibernate-validator:jar:6.0.9.Final:compile
[INFO] |  |  +- javax.validation:validation-api:jar:2.0.1.Final:compile
[INFO] |  |  +- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile
[INFO] |  |  \- com.fasterxml:classmate:jar:1.3.4:compile
[INFO] |  \- org.springframework:spring-test:jar:5.0.4.RELEASE:test
[INFO] +- org.springframework.roo:org.springframework.roo.annotations:pom:2.0.0.RELEASE:compile
[INFO] |  +- org.springframework.roo:org.springframework.roo.addon.configurable.annotations:jar:2.0.0.RELEASE:compile
[INFO] |  +- org.springframework.roo:org.springframework.roo.addon.javabean.annotations:jar:2.0.0.RELEASE:compile
[INFO] |  +- org.springframework.roo:org.springframework.roo.addon.jpa.annotations:jar:2.0.0.RELEASE:compile
[INFO] |  +- org.springframework.roo:org.springframework.roo.addon.layers.repository.jpa.annotations:jar:2.0.0.RELEASE:compile
[INFO] |  +- org.springframework.roo:org.springframework.roo.addon.layers.service.annotations:jar:2.0.0.RELEASE:compile
[INFO] |  +- org.springframework.roo:org.springframework.roo.addon.plural.annotations:jar:2.0.0.RELEASE:compile
[INFO] |  +- org.springframework.roo:org.springframework.roo.addon.security.annotations:jar:2.0.0.RELEASE:compile
[INFO] |  +- org.springframework.roo:org.springframework.roo.addon.web.mvc.controller.annotations:jar:2.0.0.RELEASE:compile
[INFO] |  +- org.springframework.roo:org.springframework.roo.addon.web.mvc.exceptions.annotations:jar:2.0.0.RELEASE:compile
[INFO] |  +- org.springframework.roo:org.springframework.roo.addon.web.mvc.thymeleaf.annotations:jar:2.0.0.RELEASE:compile
[INFO] |  +- org.springframework.roo:org.springframework.roo.classpath:jar:2.0.0.RELEASE:compile
[INFO] |  |  +- org.apache.felix:org.apache.felix.scr.annotations:jar:1.9.12:compile
[INFO] |  |  +- org.springframework.roo:org.springframework.roo.file.monitor:jar:2.0.0.RELEASE:compile
[INFO] |  |  +- org.springframework.roo:org.springframework.roo.file.undo:jar:2.0.0.RELEASE:compile
[INFO] |  |  +- org.springframework.roo:org.springframework.roo.metadata:jar:2.0.0.RELEASE:compile
[INFO] |  |  +- org.springframework.roo:org.springframework.roo.model:jar:2.0.0.RELEASE:compile
[INFO] |  |  +- org.springframework.roo:org.springframework.roo.process.manager:jar:2.0.0.RELEASE:compile
[INFO] |  |  |  \- org.springframework.roo:org.springframework.roo.shell.osgi:jar:2.0.0.RELEASE:compile
[INFO] |  |  +- org.springframework.roo:org.springframework.roo.project:jar:2.0.0.RELEASE:compile
[INFO] |  |  |  \- org.apache.felix:org.apache.felix.framework:jar:5.4.0:compile
[INFO] |  |  +- org.springframework.roo:org.springframework.roo.shell:jar:2.0.0.RELEASE:compile
[INFO] |  |  +- org.springframework.roo:org.springframework.roo.support:jar:2.0.0.RELEASE:compile
[INFO] |  |  +- org.springframework.roo:org.springframework.roo.settings:jar:2.0.0.RELEASE:compile
[INFO] |  |  |  \- org.springframework.roo:org.springframework.roo.propfiles.manager:jar:2.0.0.RELEASE:compile
[INFO] |  |  \- org.springframework.roo.wrapping:org.springframework.roo.wrapping.inflector:jar:0.7.0.010:compile
[INFO] |  +- org.springframework.roo:org.springframework.roo.addon.dto.annotations:jar:2.0.0.RELEASE:compile
[INFO] |  \- org.springframework.roo:org.springframework.roo.addon.ws.annotations:jar:2.0.0.RELEASE:compile
[INFO] +- com.sac.enax.test:enax_bdd_test_core:jar:1.1.7:compile
[INFO] |  +- org.glassfish.jersey.core:jersey-common:jar:2.14:compile
[INFO] |  |  +- javax.ws.rs:javax.ws.rs-api:jar:2.0.1:compile
[INFO] |  |  +- org.glassfish.jersey.bundles.repackaged:jersey-guava:jar:2.14:compile
[INFO] |  |  +- org.glassfish.hk2.external:javax.inject:jar:2.4.0-b06:compile
[INFO] |  |  +- org.glassfish.hk2:hk2-locator:jar:2.4.0-b06:compile
[INFO] |  |  \- org.glassfish.hk2:osgi-resource-locator:jar:1.0.1:compile
[INFO] |  +- javax.inject:javax.inject:jar:1:compile
[INFO] |  +- org.glassfish.hk2:hk2:jar:2.4.0-b06:compile
[INFO] |  |  +- org.glassfish.hk2:config-types:jar:2.4.0-b06:compile
[INFO] |  |  +- org.glassfish.hk2:core:jar:2.4.0-b06:compile
[INFO] |  |  +- org.glassfish.hk2:hk2-config:jar:2.4.0-b06:compile
[INFO] |  |  |  +- org.jvnet:tiger-types:jar:1.4:compile
[INFO] |  |  |  \- org.glassfish.hk2.external:bean-validator:jar:2.4.0-b06:compile
[INFO] |  |  +- org.glassfish.hk2:hk2-runlevel:jar:2.4.0-b06:compile
[INFO] |  |  \- org.glassfish.hk2:class-model:jar:2.4.0-b06:compile
[INFO] |  |     \- org.glassfish.hk2.external:asm-all-repackaged:jar:2.4.0-b06:compile
[INFO] |  +- com.google.inject:guice:jar:4.0:compile
[INFO] |  +- commons-io:commons-io:jar:2.4:compile
[INFO] |  +- org.apache.commons:commons-lang3:jar:3.8.1:compile
[INFO] |  +- info.cukes:gherkin:jar:2.12.2:compile
[INFO] |  +- com.jayway.jsonpath:json-path-assert:jar:2.1.0:compile
[INFO] |  |  \- com.jayway.jsonpath:json-path:jar:2.1.0:compile
[INFO] |  |     \- net.minidev:json-smart:jar:2.2:compile
[INFO] |  |        \- net.minidev:accessors-smart:jar:1.1:compile
[INFO] |  +- com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.7.1:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.15:compile
[INFO] |  +- com.github.fge:json-schema-validator:jar:2.2.6:compile
[INFO] |  |  +- com.google.code.findbugs:jsr305:jar:3.0.0:compile
[INFO] |  |  +- joda-time:joda-time:jar:2.3:compile
[INFO] |  |  +- com.googlecode.libphonenumber:libphonenumber:jar:6.2:compile
[INFO] |  |  +- com.github.fge:json-schema-core:jar:1.2.5:compile
[INFO] |  |  |  +- com.github.fge:uri-template:jar:0.9:compile
[INFO] |  |  |  |  \- com.github.fge:msg-simple:jar:1.1:compile
[INFO] |  |  |  |     \- com.github.fge:btf:jar:1.2:compile
[INFO] |  |  |  +- com.github.fge:jackson-coreutils:jar:1.8:compile
[INFO] |  |  |  \- org.mozilla:rhino:jar:1.7R4:compile
[INFO] |  |  +- javax.mail:mailapi:jar:1.4.3:compile
[INFO] |  |  \- net.sf.jopt-simple:jopt-simple:jar:4.6:compile
[INFO] |  +- org.springframework:spring-context:jar:4.2.3.RELEASE:compile
[INFO] |  +- org.slf4j:slf4j-api:jar:1.7.5:compile
[INFO] |  +- org.slf4j:jcl-over-slf4j:jar:1.7.7:compile
[INFO] |  +- org.slf4j:slf4j-log4j12:jar:1.7.12:compile
[INFO] |  +- com.tngtech.java:junit-dataprovider:jar:1.5.0:compile
[INFO] |  |  \- junit:junit-dep:jar:4.8.2:compile
[INFO] |  +- info.cukes:cucumber-java:jar:1.2.2:compile
[INFO] |  |  \- info.cukes:cucumber-core:jar:1.2.2:compile
[INFO] |  |     +- info.cukes:cucumber-html:jar:0.2.3:compile
[INFO] |  |     \- info.cukes:cucumber-jvm-deps:jar:1.0.3:compile
[INFO] |  +- info.cukes:cucumber-junit:jar:1.2.2:compile
[INFO] |  +- org.powermock:powermock-module-junit4:jar:1.7.3:test
[INFO] |  +- org.powermock:powermock-api-mockito:jar:1.5.5:compile
[INFO] |  +- org.powermock:powermock-api-support:jar:1.4.12:compile
[INFO] |  |  +- org.powermock:powermock-core:jar:1.4.12:compile
[INFO] |  |  \- org.powermock:powermock-reflect:jar:1.4.12:compile
[INFO] |  +- org.powermock:powermock-module-junit4-common:jar:1.4.12:compile
[INFO] |  +- com.google.code.findbugs:annotations:jar:1.3.9:compile
[INFO] |  \- com.sac.enax.jjschema:jjschema:jar:0.9:compile
[INFO] |     \- com.fasterxml.jackson.module:jackson-module-jsonSchema:jar:2.1.0:compile
[INFO] +- com.sac.enax.global.bdd:enax_bdd_test_impl:jar:1.1.5:compile
[INFO] +- org.glassfish.hk2:hk2-api:jar:2.5.0-b61:test
[INFO] |  +- org.glassfish.hk2:hk2-utils:jar:2.5.0-b61:compile
[INFO] |  \- org.glassfish.hk2.external:aopalliance-repackaged:jar:2.5.0-b61:compile
[INFO] +- com.google.guava:guava:jar:18.0:compile
[INFO] +- org.apache.httpcomponents:httpclient:jar:4.5.1:test
[INFO] |  +- commons-logging:commons-logging:jar:1.2:compile
[INFO] |  \- commons-codec:commons-codec:jar:1.9:compile
[INFO] +- org.apache.httpcomponents:httpcore:jar:4.4.3:test
[INFO] +- com.sun.jersey:jersey-core:jar:1.19.2:test
[INFO] |  \- javax.ws.rs:jsr311-api:jar:1.1.1:test
[INFO] +- uk.co.jemos.podam:podam:jar:7.2.3.RELEASE:compile
[INFO] |  +- net.jcip:jcip-annotations:jar:1.0:compile
[INFO] |  \- javax.annotation:javax.annotation-api:jar:1.3.2:compile
[INFO] +- com.sac.jee.arq.spring.core:arq-spring-backend-commons:jar:5.4.2.0:compile
[INFO] |  +- com.sac.jee.arq.spring.core:arq-spring-core-api:jar:5.4.4.0:compile
[INFO] |  |  +- com.sac.secarq.caas2:caascore-channel-infrastructure-seg:jar:1.0.11:compile
[INFO] |  |  +- org.apache.cxf:cxf-rt-rs-extension-search:jar:3.2.4:compile
[INFO] |  |  \- com.googlecode.json-simple:json-simple:jar:1.1.1:compile
[INFO] |  +- javax.persistence:persistence-api:jar:1.0:compile
[INFO] |  +- org.springframework:spring-aspects:jar:5.0.4.RELEASE:compile
[INFO] |  +- org.aspectj:aspectjrt:jar:1.9.0:compile
[INFO] |  +- org.aspectj:aspectjtools:jar:1.9.0:compile
[INFO] |  +- org.aspectj:aspectjweaver:jar:1.9.0:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.5:compile
[INFO] |  \- org.reflections:reflections:jar:0.9.8:compile
[INFO] |     +- javassist:javassist:jar:3.12.1.GA:compile
[INFO] |     \- dom4j:dom4j:jar:1.6.1:compile
[INFO] |        \- xml-apis:xml-apis:jar:1.0.b2:compile
[INFO] +- org.mapstruct:mapstruct-jdk8:jar:1.2.0.Final:compile
[INFO] +- com.sac.enax:enax_validation:jar:1.0.4:compile
[INFO] |  +- com.sac.jee.arq.spring.core:arq-spring-restutils:jar:5.4.0.0:compile
[INFO] |  |  +- cz.jirutka.rsql:rsql-parser:jar:2.1.0:compile
[INFO] |  |  +- org.springframework.data:spring-data-jpa:jar:2.0.4.RELEASE:compile
[INFO] |  |  |  +- org.springframework.data:spring-data-commons:jar:2.0.4.RELEASE:compile
[INFO] |  |  |  \- org.springframework:spring-orm:jar:5.0.4.RELEASE:compile
[INFO] |  |  \- org.hibernate.javax.persistence:hibernate-jpa-2.1-api:jar:1.0.2.Final:compile
[INFO] |  +- com.sac.jee.arq.spring.core:arq-spring-core-spi:jar:1.8.1:compile
[INFO] |  \- com.sac.jee.arq.spring.core:arq-spring-connector-host-api:jar:1.8.0:compile
[INFO] |     \- org.springframework:spring-aop:jar:3.2.3.RELEASE:compile
[INFO] +- org.hibernate.validator:hibernate-validator-annotation-processor:jar:6.0.9.Final:compile
[INFO] +- javax.el:javax.el-api:jar:3.0.1-b06:compile
[INFO] +- org.glassfish.web:javax.el:jar:2.2.6:compile
[INFO] +- junit:junit:jar:4.9:test
[INFO] |  \- org.hamcrest:hamcrest-core:jar:1.1:compile
[INFO] +- com.fasterxml.jackson.core:jackson-core:jar:2.9.9:compile
[INFO] +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.5:compile
[INFO] +- org.mockito:mockito-all:jar:1.9.5:test
[INFO] +- org.mockito:mockito-core:jar:2.13.0:test
[INFO] |  +- net.bytebuddy:byte-buddy:jar:1.8.17:compile
[INFO] |  +- net.bytebuddy:byte-buddy-agent:jar:1.7.9:test
[INFO] |  \- org.objenesis:objenesis:jar:2.6:compile
[INFO] \- com.openpojo:openpojo:jar:0.8.9:compile

I don't find the problem with the hk2 jar, maybe it's not compatible with some other dependency.


Answer:

You have two different versions of hk2, the first comes transitively from here:

[INFO] +- com.sac.enax.test:enax_bdd_test_core:jar:1.1.7:compile
[INFO] |  +- org.glassfish.hk2:hk2:jar:2.4.0-b06:compile

the second as a direct dependency here:

[INFO] +- org.glassfish.hk2:hk2-api:jar:2.5.0-b61:test
[INFO] |  +- org.glassfish.hk2:hk2-utils:jar:2.5.0-b61:compile

The method org.glassfish.hk2.utilities.general.GeneralUtilities.getSystemProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; was present in version 2.4.0-b06 of hk2-utils, but then removed before version 2.5.0-b61. Edit your pom to adjust the explicitly declared dependency to 2.4.0-b06, or the intermediate dependency that pulls the older version to something newer.

Question:

I have a problem using the glue option when running Cucumber tests. Here's my test runner class:

@RunWith(Cucumber.class)
@CucumberOptions(features="src/test/java/com/xcase/tests/cucumber/features/api/APITest.feature",glue={"com.xcase.tests.cucumber.stepdefinitions.api"})
public class APIRunnerTest {

}

I run the tests along these lines:

mvn clean test -Dtest=APIRunnerTest

If I put all of my step definitions in a single class in the glue package, com.xcase.tests.cucumber.stepdefinitions.api.FirstSteps, then my tests run fine.

If I add an empty class to the com.xcase.tests.cucumber.stepdefinitions.api package, say com.xcase.tests.cucumber.stepdefinitions.api.SecondSteps,then my tests run fine. However, if I modify SecondSteps to extend FirstSteps, then my tests stop running completely! Why is that?

This is a problem for me because I'd like to put some shared step definitions and fields in a base step definition class and then have multiple classes that extend the base class. How should I do this?


Answer:

However, if I modify SecondSteps to extend FirstSteps, then my tests stop running completely! Why is that?

You now have two classes that declare steps. And because SecondSteps extends FirstSteps, SecondSteps will declare the same exact steps as FirstSteps. So Cucumber can't decide which steps should be run.

This is a problem for me because I'd like to put some shared step definitions and fields in a base step definition class and then have multiple classes that extend the base class. How should I do this?

If you want to share information between steps you should use a world object. The documentation uses ruby but after adding cucumber-pico as a dependency it works the same way in Java. For a dated tutorial check Sharing state between steps in Cucumber-JVM using PicoContainer

Question:

is it possible to use a list of things in a Cucumber data table?

A possible example is to schedule a meeting. I have a meeting with a set date, topic and a list of attendants which i want to check in my acceptance test.

Feature:
   Scenario:
      Given I want to save a meeting with the following set of data
      | Date | Attendants | Topic
      | 2017-03-12 | Jobs, Steve; Reznik, Trevor | Beer is great
      Then is the data successfully saved

How do i correctly pass a list of attendants to the test? Is this possible at all? I could only find examples of single-column tables that make up lists, but I need something nested here.


Answer:

For my tests, I simply use a special delimiter like you are doing and then parse out the result in the .rb file.

A have this more complex example for instance:

  And there are results:
     | sequence        | user   | steps                       |
     | Style Test 1    | tracy  | 1;0;pass 2;1;fail 4;1;fail  |

And my parsing code looks like:

Given(/^there are results:$/) do |table|

  table.hashes.each do |s|

     sequence = Sequence.where(name: s[:sequence]).first
     result = FactoryGirl.build(:sequence_result)
     result.sequence = sequence._id.to_s
     result.user = User.where(name: s[:user]).first._id.to_s

     s[:steps].split(" ").each do |st|
        step = FactoryGirl.build(:step_result)

        parts = st.split(";")
        step.step = sequence.steps[parts[0].to_i]._id.to_s
        step.answer = parts[1]
        step.pass = parts[2] == "pass"

        result.step_results << step
     end

     result.save

  end

end

Hope this helps :-)

Question:

I want to run a scenario in multiple browsers by tagging it with the desired browser(s).

For example:

Feature: Smoke Test
    @Chrome @Firefox
    Scenario: the site should launch in all browsers
        Given the site is online
        When I navigate to site
        Then the site should display in all browsers

I am currently able to run tests on one browser at a time with:

Feature: Smoke Test
    @Chrome
    Scenario: the site should launch in all browsers
        Given the site is online
        When I navigate to site
        Then the site should display in all browsers

    @Firefox
    Scenario: the site should launch in all browsers
        Given the site is online
        When I navigate to site
        Then the site should display in all browsers

How can this be implemented? Or, if it cannot, why?


Answer:

If you use JUnit to run your scenarios you can use @CucumberOptions to specify which tags to execute, and use separate test classes for the two tags:

@RunWith(Cucumber.class)
@CucumberOptions(tags = "@Chrome")
public class ChromeTest { }

@RunWith(Cucumber.class)
@CucumberOptions(tags = "@Firefox")
public class FirefoxTest { }

Launching of the browser should be possible with scenario hooks, which can also specify to which tags they apply:

@Before("@Chrome")
public void launchChrome() {
}

Question:

I want to run a feature file in three different browsers parallely. How can I create three different instances of webdriver? and please add How to do the same for two different feature files?

P.S. I am working on cucumber with java.


Answer:

When you mention "three different browsers in parallel" do you mean like Chrome, Firefox and explorer running in parallel OR three different instances of Chrome only.

If it is the second case refer to this article - https://opencredo.com/running-cucumber-jvm-tests-in-parallel/. The basic logic behind this is forking into separate JVM's for the number of parallel instances required. This is done using Maven surefire plugin.

If the first case then you will need to modify certain aspects. The plugin passes the 'fork number' to the JVM which you can use to instantiate the specific browser driver for that JVM.

I am using Java 8, junit 4.12, picocontainer for Dependency Injection, Maven 3 (will not work with lower versions as 'fork number' passes null), selenium 2.53 (u need to figure out code changes for Selenium 3 if required in driver creation) and browsers Chrome and Firefox (you need to add code for IE).

Code

  1. Changes to ShareDriver.java from article github - Overwrite the static block with this and add other methods.
static {
      instantiateDriver();        
        Runtime.getRuntime().addShutdownHook(CLOSE_THREAD);
}

private static void instantiateDriver() {

      //numFork will be passed in the maven command line or eclipse 
      //--- clean install -DnumFork=${surefire.forkNumber}
      int browserType = Integer.parseInt(System.getProperty("numFork"));

      System.out.println("BROWSER TYPE "+browserType);

      if(browserType == 1)
          instantiateChromeDriver();

      else if (browserType == 2)
          instantiateFirefoxDriver();

      else if (browserType == 3) {    
          instantiateIEDriver();
      }       

  }

  private static void instantiateIEDriver() {
      //Implement this
  }

  private static void instantiateFirefoxDriver() {

      REAL_DRIVER = new FirefoxDriver();
      REAL_DRIVER.manage().window().maximize();   
  }

  private static void instantiateChromeDriver() {

      System.setProperty("webdriver.chrome.driver", "location of chromedriver.exe");
      ChromeOptions chop =  new ChromeOptions();
      chop.addArguments("test-type");
      chop.addArguments("start-maximized");
      chop.addArguments("--disable-extensions");

      REAL_DRIVER = new ChromeDriver(chop);
  }
  1. Changes to feature files - Remove the tags. Change one of the feature files to contain some other steps. Code the new steps in step definition class.

  2. Changes to runner classes - Remove the tag option from cucumberoptions, you may need to add glue option to point to your step definition class. So effectively both the runner classes are the same. You can remove one of the runner classes if you want. Else tests will be repeated twice in each browser.

  3. pom.xml - Make sure that the number of forks defined (<surefire.fork.count>5</surefire.fork.count>) is more than the number of browsers you are using. Else the logic will fail.

Running in Maven -- You can run from eclipse plugin using command clean install -DnumFork=${surefire.forkNumber} in goals option. Or from command line using mvn clean install -DnumFork=${surefire.forkNumber}.

This should run all the scenarios in all the feature files in all the browser instances. You can refine the cucumberoptions such as tags and feature to run specific scenarios or feature files.

Question:

Hi Im trying to add a bearer token to a retrofit call in java, but i cant seem to pass it.

Currently Im logging in with one method and this creates a bearer token and im trying to add the token to the Get Call, but its just returning a 401 error, have I added the token to the call correctly?

@GET("diagnosis/configuration")
Call<ResponseBody> getFavourites (@Query("favourite") Boolean fave,@Header("Bearer Token") String authHeader);

@POST("auth/login")
Call<LoginResponse> postLogin (@Body LoginCredentialsBody body);



public class LoginApiStepDefinition extends TestBaseFix {

Retrofit retrofit = super.buildRetrofit(super.buildOkHttpClient());
RetrofitCallsLogin call = retrofit.create(RetrofitCallsLogin.class);
RetrofitCallsGetFavourites favecall = retrofit.create(RetrofitCallsGetFavourites.class);

private Response<LoginResponse> responseBody;
private String favouritesResponseBody;


String usernameValue;
String passwordValue;


@And("I login with {string} and {string} to return login token")
public void iLoginWithAndToReturnLoginToken(String username, String password) throws Exception {

    LoginApi(username, password);

}


public String LoginApi(String username, String password) throws Exception {


    usernameValue = username;
    passwordValue = password;

    //gets fixture ids for the dates
    LoginCredentialsBody login = new LoginCredentialsBody();
    login.setPassword(passwordValue);
    login.setUsername(usernameValue);
    String responseBody = call.postLogin(login).execute().body().toString();
    String requiredString = responseBody.substring(responseBody.indexOf("=") + 1, responseBody.indexOf(","));


    System.out.println(requiredString);


    return token;


}



@Then("I get the list of favourites with {string} and {string}")
public void iGetTheListOfFavouritesWithAnd(String username, String password) throws Exception {

    String favouritesResponseBody = favecall.getFavourites(true, LoginApi(username, password)).execute().body().toString();
    System.out.println(favouritesResponseBody);
}

}


Answer:

To add bearer token in retrofit, you have to create a class that implements Interceptor

public class TokenInterceptor implements Interceptor{

    @Override
    public Response intercept(Chain chain) throws IOException {

       //rewrite the request to add bearer token
        Request newRequest=chain.request().newBuilder()
                .header("Authorization","Bearer "+ yourtokenvalue)
                .build();

        return chain.proceed(newRequest);
    }
}

Now add your Interceptor class in OKHttpClient object and add that obejct in Retrofit object:

TokenInterceptor interceptor=new TokenInterceptor();

OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(interceptor).
            .build();

Retrofit retrofit = new Retrofit.Builder()
            .client(client)
            .baseUrl("add your url here")
            .addConverterFactory(JacksonConverterFactory.create())
            .build();

Question:

I can't create step definition of bdd sentences which ends with some punctuation mark.

It creates this sentences as 'null'

When I search "user X" in search field 'id (username)'
And I click on search button
@When("null")
    public void ıSearchInSearchFieldidUsername(String arg0) {
    }

I expect something like that:

@When("^I search \"([^\"]*)\" in search field 'id (username)")

Edit: I've just got same result for this sentence also:

When I search "user X" in search field 'id. username'

Answer:

Gherkin is meant to be a more natural language expression of the business requirements, not the actual syntax from the developer. In other words, you probably want to simply describe the field instead of using the exact field name from code. There is no need to make a variable (using quotation marks or other special characters) in that sentence unless you intend to use it in your test code. But it looks like in this example you don't have any alternate variables to supply, it appears you are only setting up the scenario. So just describe the basic scenario. Try something that sounds more like natural language, like:

When I enter a name in the username search field
And I click on the search button

Check the Gherkin documentation to see how to use variables and other special characters.

Question:

I'm currently learning cucumber and in very simple test, i had some doubts: "How is the best way to organize my StepClasses.

This is my .feature:

Feature: How many potatoes have in the sack

Scenario: I put one potato in the Bag
    Given the bag has 10 potatoes
    When I put 1 potato
    Then I should be told 11 potatoes

  Scenario: I remove one potato from the Bag
    Given the bag has 10 potatoes
    When I remove 1 potato
    Then I should be told 9 potatoes

And my StepClass:

public class Stepdefs {

private Integer potatoesInTheBag;

@Given("^the bag has 10 potatoes$")
public void the_bag_has_10_potatoes(){
    this.potatoesInTheBag=10;
}

@When("^I put 1 potato$")
public void i_put_one_potato(){
    this.potatoesInTheBag = potatoesInTheBag + 1;
}

@Then("^I should be told (\\d+) potatoes$")
public void i_should_be_told_potatoes(int potatoes) throws Exception {
    assertEquals(potatoesInTheBag.intValue(),potatoes);
}

@When("^I remove 1 potato$")
public void i_remove_one_potato(){
    this.potatoesInTheBag = potatoesInTheBag - 1;
}

}

This example works fine, but should i_remove_one_potato() stay in here, or in another step class ? Another question, if i want to use Scenario Outline, how i would do that in this case ? Because the answers would be different although the potato added/remove would be the same. There are good practices that guide this process of structuring your cucumber tests ?

Thx


Answer:

As far the Step is relevant to the scenario to be tested it will be good to find the steps in single Step Class file. and for scenario outline it could be like: Add/Remove potatoes from bag.

:Use variables in scenario like Given the bag has "10" potatoes instead of one which you use it will help in long run.

Question:

Folder structure

I am trying to create step definition from the feature file, but the steps in feature file does not get highlighted even if i press alt+enter. (Please refer to the image and ignore the ":")

But the same was working a couple of days back, so not sure whether I messed up something.

Please let me know my mistake


Answer:

OK so i figured out the problem. I had installed a cucumber.js few month back which was causing the problem. I uninstalled cucmber.js though my IDE and then just used cucumber java and it worked fine.

Question:

I have some scenarios which call a stepdef from a jar included as a dependency.

Now, I want to maintain 2 separate versions for the same stepdef into 2 different jars. Since I need few scenarios to use version 1 and others to use version 2 of the stepdef.

How do I do this with @CucumberOptions, specifically mentioning jar source in the glue?


Answer:

As far as i know it is not supported in cucumber. We are using QAF-gherkin which support steps in jar and two different implementation for same step with support to load appropriate implementation at run time using step.provider.pkg property.

Question:

I am trying to filter what features in my test suite.

I need to specify what features/folders with features cucumber should run.

I am running that with command line, specifying single feature path works fine:

-D cucumber.options="features/Login.feature"

but I am unable to pass multiple features/paths, I tried with many ways, ex:

-D cucumber.options="features/Login.feature, features/sub_folder"

but it fails, I am well aware of tags to filter what scenarios to run or not, but it would greatly benefit my particular case if I could pass what features/folders with features cucumber should take, thank you.


Answer:

Found answer with trial and error approach:

there is no need for a comma (',') between paths to the features of folders.

Working example:

-D cucumber.options="features/Login.feature features/sub_folder"

Question:

Recently got the code to write bdd tests with cucumber on Java. There is already maven project with couple of tests and test framework. I need to continue writing bdd tests using this framework. I am writing API tests and try to run them and i get the error. I found where it fails to run further but I want to figure out what's the idea of doing so in the code. Let me share some code:

So the test framework is collecting info about the API host name this way:

public class AnyClass {

   private static final String API_HOSTNAME = "hostname";

   private static String getAPIHostName() {
      String apiHostName = System.getProperty(API_HOSTNAME);

...

}

When i leave it as is, and run the test, i get the error that host name is empty.

Can you advise on what might be expected to have under System property key "hostname"?

p.s. I tried to use http://localhost and http://127.0.0.1, where my api is located instead of assigning system property but it cannot find such host name.


Answer:

Can you advise on what might be expected to have under System property key "hostname"?

Yes, I needed to run tests in command line with the syntax like: mvn clean verify -Dhostname=http://127.0.0.1:8080

Question:

I have different tests scenarios written in cucumber/selenium using java, and usually I run tests from different features files using Tags like this mvn test -Dcucumber.options="src/test/resources/step_definitions --tags @Tagname"

What I want to do is close browser instance after all my tagged tests are run. How can I do that? @AfterSuit is not helping.


Answer:

You can use the @After of cucumber to close your browser instances. Use the tag on a method in any of your step definition class. This will fire after every scenario is executed. If you are using a shared webdriver which runs all the scenarios in a single browser then this will not work as it will close the browser after every scenario.

In that case you will need to add a shutdown hook to your shared webdriver class which will shut it down when the JVM exists.