cucumber-jvm Duplicate step definitions error

4,458 views
Skip to first unread message

bond_007

unread,
Sep 3, 2012, 6:21:13 AM9/3/12
to cu...@googlegroups.com
Hi all,

Problem
I am new here in cucumber-jvm, I have used j-behave earlier
I have started using cucumber-jvm in my company. I have  two differnet feature files
Each feature file has common step like Given I am in the home page,  but each feature file has it own corresponding step definition java file.
But it seems cucumber don't like have common step definition mentioned separtely in two differnent step definition java file
I know this is common scenario, may be I am missing something
If I cant have common step defintion in two diffent java file, what is alternative. Do I need to keep common steps like login to home page
in some different class? If yes, please let me know how. Thanks bond.

When I run the command
mvn -e -Dtest=DeleteRecordTest clean test
I get the following
Tests in error:
  initializationError(com.company_name.projectname.test.DeleteRecordTest): Duplicate step definitions in com.company_name.projectname.steps.DeleteRecordStepdefs.i_am_on_the_home_page() in file:/C:/workspace/project-name/target/test-classes/ and com.company_name.projectname.steps.AddRecordTestStepdefs.i_am_on_the_home_page() in file:/
C:/workspace/project-name/target/test-classes/


Feature file
-------------------------------
addRecord.feature
Feature: add a record
As a user I want to add items from home page   

    Scenario: add item
Given I am on the home page
When I click the add items in the home page 
Then the added item should be added to the list
deleterecord.feature
Feature: add a record
As a user I want to delete items from home page   

    Scenario: add item
Given I am on the home page
When I click the delete items in the home page 
Then a confirmation message should be displayed
And the item should be removed to the list
===============================

package structure
------------------
src/main/java
com.company_name.projectname.pages

src/test/resources
com.company_name.projectname.cucumber
addRecord.feature
deleteRecord.feature

src/test/java
com.company_name.projectname.steps
AddRecordStepdefs.java
DeleteRecordStepdefs.java
com.company_name.projectname.test
AddRecordTest.java
DeleteRecordTest.java




aslak hellesoy

unread,
Sep 3, 2012, 6:27:20 AM9/3/12
to cu...@googlegroups.com
On Mon, Sep 3, 2012 at 11:21 AM, bond_007 <agile...@gmail.com> wrote:
> Hi all,
>
> Problem
> I am new here in cucumber-jvm, I have used j-behave earlier
> I have started using cucumber-jvm in my company. I have two differnet
> feature files
> Each feature file has common step like Given I am in the home page, but
> each feature file has it own corresponding step definition java file.

That's not the right way to organise things. Please read:

* https://github.com/cucumber/cucumber/wiki/Feature-Coupled-Step-Definitions-(Antipattern)
* https://github.com/cucumber/cucumber/wiki/Step-Organisation

> But it seems cucumber don't like have common step definition mentioned
> separtely in two differnent step definition java file

That's right. I suggest you create a NavigationStepdefs class and
define your i_am_on_the_home_page() stepdef there.

Aslak
> --
> -- Rules --
>
> 1) Please prefix the subject with [Ruby], [JVM] or [JS].
> 2) Please use interleaved answers
> http://en.wikipedia.org/wiki/Posting_style#Interleaved_style
> 3) If you have a question, don't reply to an existing message. Start a new
> topic instead.
>
> You received this message because you are subscribed to the Google Groups
> Cukes group. To post to this group, send email to cu...@googlegroups.com. To
> unsubscribe from this group, send email to
> cukes+un...@googlegroups.com. For more options, visit this group at
> https://groups.google.com/d/forum/cukes?hl=en
>
>

bond_007

unread,
Sep 3, 2012, 8:21:25 AM9/3/12
to cu...@googlegroups.com
Thanks for the prompt reply
I am trying use cucumber-jvm to driver web  automation using webdriver  along with page object automation framework
I am not sure how I can keep  common steps in separate class considering that all the page objects constructor needs to have same driver (Webdriver  object) passed. Is there any link which shows webdriver/pageobject framework is used along with cucumber-jvm

aslak hellesoy

unread,
Sep 3, 2012, 8:30:25 AM9/3/12
to cu...@googlegroups.com
On Mon, Sep 3, 2012 at 1:21 PM, bond_007 <agile...@gmail.com> wrote:
> Thanks for the prompt reply
> I am trying use cucumber-jvm to driver web automation using webdriver
> along with page object automation framework
> I am not sure how I can keep common steps in separate class considering
> that all the page objects constructor needs to have same driver (Webdriver
> object) passed.

Just let the stepdef classes that need a WebDriver instance declare
one in a constructor instead of instantiating your own.
Cucumber-JVM will use Dependency Injection to inject the same
WebDriver instance into all objects that need one.

See this example:
https://github.com/cucumber/cucumber-jvm/tree/master/examples/java-webbit-websockets-selenium

Aslak

bond_007

unread,
Sep 3, 2012, 9:11:46 AM9/3/12
to cu...@googlegroups.com
Ok, I will do that
Do I need to do anything special apart from using Webdriver object in the constructor, to let cucumber-jvm to do the dependency injection
Thanks

aslak hellesoy

unread,
Sep 3, 2012, 9:48:39 AM9/3/12
to cu...@googlegroups.com
On Mon, Sep 3, 2012 at 2:11 PM, bond_007 <agile...@gmail.com> wrote:
> Ok, I will do that
> Do I need to do anything special apart from using Webdriver object in the
> constructor, to let cucumber-jvm to do the dependency injection

Just make sure you understand what's going on in the example I linked
to and ask if something is not clear.

Aslak

bond_007

unread,
Sep 3, 2012, 10:25:59 AM9/3/12
to cu...@googlegroups.com
I did similar to shown in the link, used SharedDriver as constructor argument, but gave following error
I see cucumber-picocontainer version 1.0.10 in maven local repository. Not sure what could be problem

NavigationStepdefs doesn't have an empty constructor. If you need DI, put cucumber-picocontainer on the classpath

aslak hellesoy

unread,
Sep 3, 2012, 10:30:10 AM9/3/12
to cu...@googlegroups.com
On Mon, Sep 3, 2012 at 3:25 PM, bond_007 <agile...@gmail.com> wrote:
> I did similar to shown in the link, used SharedDriver as constructor
> argument, but gave following error
> I see cucumber-picocontainer version 1.0.10 in maven local repository. Not
> sure what could be problem
>

The problem is what the error message says. You're now using DI
(Dependency Injection) and need to add cucumber-picocontainer to the
classpath.

bond_007

unread,
Sep 3, 2012, 10:51:24 AM9/3/12
to cu...@googlegroups.com
It is there in the dependency in pom.xml . May be I need to change the scope 

bond_007

unread,
Sep 3, 2012, 11:12:00 AM9/3/12
to cu...@googlegroups.com
I believe somewhere i need to change in the scope or packagestructure . 
At the moment , I have the following , do I need change scope of any of the to something different

<dependencies>
       <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-picocontainer</artifactId>
            <version>${cucumber.jvm.version}</version>
            <scope>compile</scope>
        </dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-firefox-driver</artifactId>
<version>${selenium.version}</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-chrome-driver</artifactId>
<version>${selenium.version}</version>
</dependency>

<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-support</artifactId>
<version>${selenium.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-core</artifactId>
<version>${cucumber.jvm.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-java</artifactId>
<version>${cucumber.jvm.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-guice</artifactId>
<version>${cucumber.jvm.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${cucumber.jvm.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>

aslak hellesoy

unread,
Sep 3, 2012, 11:25:22 AM9/3/12
to cu...@googlegroups.com
On Mon, Sep 3, 2012 at 3:51 PM, bond_007 <agile...@gmail.com> wrote:
> It is there in the dependency in pom.xml . May be I need to change the scope
>

Can we see the relevant parts of the POM? Also, please don't top post.
(Rule 2 below)

Aslak

aslak hellesoy

unread,
Sep 3, 2012, 11:30:26 AM9/3/12
to cu...@googlegroups.com
On Mon, Sep 3, 2012 at 4:12 PM, bond_007 <agile...@gmail.com> wrote:
> I believe somewhere i need to change in the scope or packagestructure .
> At the moment , I have the following , do I need change scope of any of the
> to something different
>

First - make sure your cucumber.jvm.version is the latest - currently 1.0.14.

Second - only add *one* DI container module. One of
cucumber-picocontainer, cucumber-guice, cucumber-spring.
Can you get rid of cucumber-guice and see if that helps?

You can also omit cucumber-core - its' a transitive dependency. You
should only need the following cucumber-* deps in your POM:

cucumber-picocontainer
cucumber-junit

Aslak

bond_007

unread,
Sep 3, 2012, 12:14:00 PM9/3/12
to cu...@googlegroups.com


On Monday, September 3, 2012 4:30:49 PM UTC+1, Aslak Hellesøy wrote:
On Mon, Sep 3, 2012 at 4:12 PM, bond_007 <agile...@gmail.com> wrote:
> I believe somewhere i need to change in the scope or packagestructure .
> At the moment , I have the following , do I need change scope of any of the
> to something different
>

First - make sure your cucumber.jvm.version is the latest - currently 1.0.14.

Second - only add *one* DI container module. One of
cucumber-picocontainer, cucumber-guice, cucumber-spring.
Can you get rid of cucumber-guice and see if that helps?
 
Commenting cucumber-guice  dependency seems to have worked.
In fact, it now invoked the browser and executes the common step, but throws error while executing second step i.e When step,
problem in passing the driver instance

I now get the following error, instead of using the SahredDriver, can I use the pure webdriver of Webdriver

Exception in thread "Thread-4" org.openqa.selenium.remote.UnreachableBrowserExce
ption: Error communicating with the remote browser. It may have died.
Build info: version: '2.23.1', revision: 'unknown', time: '2012-06-08 12:33:29'
System info: os.name: 'Windows XP', os.arch: 'x86', os.version: '5.1', java.vers
ion: '1.6.0_21'
Driver info: driver.version: RemoteWebDriver
        at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.ja
va:453)
        at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.ja
va:462)
        at org.openqa.selenium.remote.RemoteWebDriver.close(RemoteWebDriver.java
:325)
        at com.pressassociation.schedules.common.SharedDriver$1.run(SharedDriver
.java:20)
Caused by: org.openqa.selenium.WebDriverException: Session ID may not be null
Build info: version: '2.23.1', revision: 'unknown', time: '2012-06-08 12:33:29'
System info: os.name: 'Windows XP', os.arch: 'x86', os.version: '5.1', java.vers
ion: '1.6.0_21'
Driver info: driver.version: RemoteWebDriver
        at org.openqa.selenium.remote.HttpCommandExecutor$CommandInfo.get(HttpCo
mmandExecutor.java:543)
        at org.openqa.selenium.remote.HttpCommandExecutor$CommandInfo.getMethod(
HttpCommandExecutor.java:527)
        at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExe
cutor.java:266)
        at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(Driv
erCommandExecutor.java:66)
        at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.ja
va:431)
        ... 3 more

aslak hellesoy

unread,
Sep 3, 2012, 12:46:34 PM9/3/12
to cu...@googlegroups.com
On Mon, Sep 3, 2012 at 5:14 PM, bond_007 <agile...@gmail.com> wrote:
>
>
> On Monday, September 3, 2012 4:30:49 PM UTC+1, Aslak Hellesøy wrote:
>>
>> On Mon, Sep 3, 2012 at 4:12 PM, bond_007 <agile...@gmail.com> wrote:
>> > I believe somewhere i need to change in the scope or packagestructure .
>> > At the moment , I have the following , do I need change scope of any of
>> > the
>> > to something different
>> >
>>
>> First - make sure your cucumber.jvm.version is the latest - currently
>> 1.0.14.
>>
>> Second - only add *one* DI container module. One of
>> cucumber-picocontainer, cucumber-guice, cucumber-spring.
>> Can you get rid of cucumber-guice and see if that helps?
>
>
> Commenting cucumber-guice dependency seems to have worked.
> In fact, it now invoked the browser and executes the common step, but throws
> error while executing second step i.e When step,
> problem in passing the driver instance
>
> I now get the following error, instead of using the SahredDriver, can I use
> the pure webdriver of Webdriver
>

What do you mean by "the pure webdriver of WebDriver"? There are many
implementations - ChromeDriver, FireFoxDriver etc.

Your stepdef constructor(s) can declare any *concrete* implementation
of WebDriver.
The SharedWebDriver in the example just delegates everything to a ChromeDriver.

It's hard to know why your code isn't working without access to your source.

Did you manage to get the example running at all? If you get it from
github you might have to change the dependency from 1.0.15-SNAPSHOT to
1.0.14 unless you `mvn install` everything from the root directory
first.

Aslak

bond_007

unread,
Sep 4, 2012, 4:24:51 AM9/4/12
to cu...@googlegroups.com
I get null point exception when it executes second(When) step, which means it does nt get proper page object handle
The Home page object created in Given step of Navigation needs to be passed to be  when step of AddRecordStepdefs, so that
home page methods like homepage.getCurrentNoOfIteminHomePage and homepage.clickAddButton(): needs to be invoked
But for some the reason, the home page created is not passed and it gives nullpoint exception
How to pass the same home page created in Given Step of  NavigationStepsStepdefs to When step of AddRecordStepdefs

Here is my code :
Navigation steps
public class NavigationStepsStepdefs {
private WebDriver driver;
private HomePage homepage;
public NavigationStepsStepdefs(SharedDriver driver){
this.driver=driver;
}
@Given("^I am on the Home page$")
public void i_am_on_the_Home_page() throws Throwable {
homepage = new HomePage(driver);
homepage.openURL("http://");
}

}

AddRecordStepdefs

public class AddRecordStepdefs {
private WebDriver driver;
private HomePage homepage;
private int count;
public AddRecordStepdefs(SharedDriver driver){
this.driver=driver;
}


@When("^I click the add items in the home page$")
public void i_click_the_add_tems_in_the_home_page(){
count = homepage.getCurrentNoOfIteminHomePage();
homepage.clickAddButton():
}

@Then("^the added item should be added to the list$")
public void the_added_item_should_be_added_to_the_list() {
assertTrue(count + 1 == homepage.getCurrentNoOfIteminHomePage());
}

}


This is Home Page class

public class HomePage extends AbstractPageObject {
private WebDriver driver;
public HomePage(WebDriver driver) {
super(driver);
this.driver = driver;
}
public void openURL(String url){
driver.get(url);
}
public void clickAddButton() {
WebElement addButton = getButtoninthePageBy(By.cssSelector(""));
addButton.click():
}
public int getCurrentNoOfIteminHomePage() {
int couunt =0
///  write the code to get current items in the home page
   return count 
}
}

aslak hellesoy

unread,
Sep 4, 2012, 4:58:47 AM9/4/12
to cu...@googlegroups.com
You're not assigning a value to AddRecordStepdefs.homepage anywhere.
Why did you expect it to be anything other than null?

Just assign one in the same way as you do it in NavigationStepsStepdefs.
You'll have 2 distinct instances of HomePage in this case, but that's
ok since they both share the same WebDriver instance.

Aslak

bond_007

unread,
Sep 4, 2012, 5:51:36 AM9/4/12
to cu...@googlegroups.com
Assuming that cucucmber/Depenecnt injection supprots steps sharing,
I thought the object created in Given part of NavigationStepsStepdefs will be retained through some dependency mechanism of cucumber

 
Just assign one in the same way as you do it in NavigationStepsStepdefs.
You'll have 2 distinct instances of HomePage in this case, but that's
ok since they both share the same WebDriver instance.

Aslak

I now added again homepage = new HomePage(driver) in Constructor of AddRecordStepdefs
It works fine as now, now no nullpoint exception comes.
But It was wondering if there alternative to re-creating same home object twice. 
Can't the object created in NavigationStepsStepdefs steps retained some way?


New error towards end of the run
towards end of the run, after closing the browser , I get error :ERROR:automation_proxy.cc(320)] Channel error in AutomationProxy
and the run stops. I had to manually terminate the job, but other than that, the run goes smoothly.
Was wondering if it some bug
 

aslak hellesoy

unread,
Sep 4, 2012, 6:25:18 AM9/4/12
to cu...@googlegroups.com
No it doesn't. That would be magical.

The only "magic" that happens is that Cucumber (via a DI engine)
invokes your constructors (reusing argument instances so different
classes can get a ref to the same objects). That's it. You have to
assign fields yourself.

>
>>
>> Just assign one in the same way as you do it in NavigationStepsStepdefs.
>> You'll have 2 distinct instances of HomePage in this case, but that's
>> ok since they both share the same WebDriver instance.
>>
>> Aslak
>
>
> I now added again homepage = new HomePage(driver) in Constructor of
> AddRecordStepdefs
> It works fine as now, now no nullpoint exception comes.
> But It was wondering if there alternative to re-creating same home object
> twice.
> Can't the object created in NavigationStepsStepdefs steps retained some way?
>

Sure - you can do this:

public class NavigationStepsStepdefs {
private final HomePage homepage;

public NavigationStepsStepdefs(HomePage homePage){
this.homePage=homePage;
}
@Given("^I am on the Home page$")
public void i_am_on_the_Home_page() throws Throwable {
homepage = new HomePage(driver);
homepage.openURL("http://");
}
}

public class AddRecordStepdefs {
private final HomePage homepage;
private int count;

public AddRecordStepdefs(HomePage homepage){
this.homepage=homepage;
}



@When("^I click the add items in the home page$")
public void i_click_the_add_tems_in_the_home_page(){
count = homepage.getCurrentNoOfIteminHomePage();
homepage.clickAddButton():
}

@Then("^the added item should be added to the list$")
public void the_added_item_should_be_added_to_the_list() {
assertTrue(count + 1 == homepage.getCurrentNoOfIteminHomePage());
}
}

public class HomePage extends AbstractPageObject {
private final WebDriver driver;
public HomePage(SharedDriver driver) {
super(driver);
this.driver = driver;

}

public void openURL(String url){
driver.get(url);

}

public void clickAddButton() {
WebElement addButton = getButtoninthePageBy(By.cssSelector(""));
addButton.click():

}

public int getCurrentNoOfIteminHomePage() {
int couunt =0
/// write the code to get current items in the home page
return count
}

}

The DI container (PicoContainer) will pass the same HomePage instance
to your two constructors. It's smart and understands the order in
which objects need to be instantiated.
It will do this using reflection:

SharedDriver driver = new SharedDriver();
HomePage homePage = new HomePage(driver);
NavigationStepsStepdefs nss = new NavigationStepsStepdefs(homePage);
AddRecordStepdefs ars = new AddRecordStepdefs(homePage);

Make it a habit to declare fields assigned via constructors as final.
That way they are never null.

Aslak

bond_007

unread,
Sep 4, 2012, 7:31:24 AM9/4/12
to cu...@googlegroups.com
Not sure what is best practise to add Home object twice or add Home Page to each constructor.
But I guess when add home page in each constructor like the way you explained, it might add the same state of hompage to each constructor, which may not be always desired one, because homepage.openURL is used
in common step  NavigationStepsStepdefs, where is in  AddRecordStepdefs, homepage object received might be of the state before openURL is invoked
Any way, thanks for your help. any idea about automation proxy error and alos screenshot method does nt seem to be taking screenshot, it may because of the automation proxy error at the end

aslak hellesoy

unread,
Sep 4, 2012, 7:46:50 AM9/4/12
to cu...@googlegroups.com
The rules of thumb are:

* Don't instantiate anything that needs to be shared. Have it injected
via the constructor instead. This ensures there is one shared instance
of everything.
* Assign injected objects to final fields.

> But I guess when add home page in each constructor like the way you
> explained, it might add the same state of hompage to each constructor, which
> may not be always desired one, because homepage.openURL is used
> in common step NavigationStepsStepdefs, where is in AddRecordStepdefs,
> homepage object received might be of the state before openURL is invoked

You'll get a new instance of your stepdef classes (and all of their
constructor dependencies) for each scenario.
No need to worry about state leaking between scenarios.

> Any way, thanks for your help. any idea about automation proxy error and
> alos screenshot method does nt seem to be taking screenshot, it may because
> of the automation proxy error at the end
>

No idea. I'd ask about that in the WebDriver forum.
The example [1] works fine for me on both Ubuntu and OS X. Haven't
tried Windows.

[1] https://github.com/cucumber/cucumber-jvm/tree/master/examples/java-webbit-websockets-selenium

Aslak

bond_007

unread,
Sep 4, 2012, 10:39:04 AM9/4/12
to cu...@googlegroups.com
Thanks  for your reply. It has been very helpful to me

bond_007

unread,
Sep 9, 2012, 3:53:19 PM9/9/12
to cu...@googlegroups.com
I want to change  my approach , now I want few page objects to be shared between two stepdefs class. eg. add object created in NavigationstepStepDefs, should be
available in AddstepDef, so that methods that need to be called from add page is available from AddstepDef.

But It seems passing more than one paramter in  NavigationstepStepDefs   constructor cause a problem for DI container , as I get error "Webdriver can not be instantiated"
Cant we pass more than one page objects in one stepDef class, so that those passed page object can be reused in another stepdef class

following are my new NavigationStepStepDef class

My NavigationstepStepDefs will have something like below
public class NavigationstepStepDefs {
    private WebDriver driver;
    private HomePage homepage;
private LoginPage loginpage;
private AddPage addpage;
private DeletePage deltepage;
public NavigationstepStepDefs(SharedDriver driver, homepage, loginpage, addpage, deletepage){
this.driver = driver
this.homepage = homepage
this.loginpage = loginpage
this.addpage = addpage
this.deletepage = deletepage
}
@Given("^I am in the Login Page$")
    public void goToLoginPage() {
        loginpage = new LoginPage(driver);
loginpage.openURL(http/)
    }
@When("^I Sign In into Home$")
    public void signIn() {
        loginpage.clickSignIn(http/)
homepage=loginpage.loginAsUser(a,b);
    }
@Given("^Iam In  Home Page$")
    public void goToHomePage() {
goToLoginPage();
signIn();
    }
@Given("^Iam In Add Page$")
    public void goToaddPage() {
goToLoginPage
signIn();
addpage =homepage.clickAddLink();
// Want this addpage available in AddSetpdefs class
    }
@Given("^Iam In Delete Page$")
    public void goTodeletePage() {
goToLoginPage
signIn();
deletepage=homepage.clickDeleteLink();
// Want this deltepage available in Deltestepdefs class
    }

Aslak Hellesøy

unread,
Sep 10, 2012, 2:27:10 AM9/10/12
to cu...@googlegroups.com, cu...@googlegroups.com
You can pass as many parameters as you want, but the parameter type must be a concrete class, not an interface. That's why I pass a SharedDriver.

Aslak

samee...@gmail.com

unread,
Feb 6, 2014, 11:06:14 AM2/6/14
to cu...@googlegroups.com
Hi,
What was the solution for this issue. I am facing similar issue.

Bilal Ejaz

unread,
Oct 7, 2014, 10:48:50 AM10/7/14
to cu...@googlegroups.com
Sameer, all you have to do is create a utility class and move your duplicate methods within them. 

i.e , if you have two methods with similar annotation, @And(I click on button), 

since you will be clicking on many buttons in your framework, move this method into utility class, cucumber automatically will recognise this method. 

I hope this helps. 
Reply all
Reply to author
Forward
0 new messages