5

I am new to Cucumber and trying to solve simple issue:

I have created a Java Project and referred all the cucumber related jars to the build-path of this project (called it "CukeTest4") and below is the structure showing the java file and feature file. When I run this feature file as Cucumber feature in Eclipse, it runs fine.

enter image description here

Now, I would like to run this from another main method. I created another Java Project, Added a Class with main method with code below which is in default package.

import cucumber.api.cli.Main;

public class UseCukeFromMain {
    public static void main(String[] args) throws Throwable 
    {
        Main.main(new String[]{"-g", "C:/work/workspaces/neon2_wks_new1/Cuketest4/src/com/cuke", "C:/work/workspaces/neon2_wks_new1/Cuketest4/src/com/cuke/cukefeature.feature"});
    }
}

I have provided implementation for the method in the java file as it works fine from Eclipse but shows the message below to implement the method

[33mU[0m

1 Scenarios ([33m1 undefined[0m)
1 Steps ([33m1 undefined[0m)
0m0.000s


You can implement missing steps with the snippets below:

@Given("^I want to write a step with precondition$")
public void i_want_to_write_a_step_with_precondition() throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}

I have tried a lot of combination for -g option, but the message is same.

EDIT2

From the comments below, adding the package to glue when the other project is in classpath, works fine.

Main.main(new String[]{"-g", "com.cuke", "C:/work/workspaces/neon2_wks_new1/Cuketest4/src/com/cuke/cukefeature.feature"};

But, Another issue:

I have some old projects that I need to integrate with cucumber. All the .class and .java are present in the folder(NO src or bin directory): C:\work\RFT_WS2\Cuketest3 , I have this directory in the Classpath. I have tried following option but unable to understand the issue:

-g "" path/to/feature //(NOT WORKING)
-g "classpath:" path/to/feature //(NOT WORKING)  
-g "Cuketest3" // Added "C:\work\RFT_WS2" in classpath (NOT WORKING) 

Now if I add the .java file to a package say "steps" and have "C:\work\RFT_WS2\Cuketest3" in classpath, option looks like

-g "steps" path/to/feature //(WORKING)

My question is that how to get it to find the methods implementation for a default package.

Also how do add multiple glue option, for example

Not Working cases I tried

Main.main(new String[]{"-g", "com.cuke,com.cuke1", "C:/work/workspaces/neon2_wks_new1/Cuketest4/src/com/cuke/cukefeature.feature"};

Main.main(new String[]{"-g", "com.cuke", "com.cuke1", "C:/work/workspaces/neon2_wks_new1/Cuketest4/src/com/cuke/cukefeature.feature"};

Thanks.

user578219
  • 597
  • 2
  • 9
  • 32
  • Use -g option as "com.cuke"... For the feature file path this should work also - "src/com/cuke/cukefeature.feature" – Grasshopper Nov 25 '17 at 15:08
  • @Grasshopper, Thanks for replying.. tried that, it doesn't work. Something very silly that I am missing or doing wrong. – user578219 Nov 25 '17 at 15:39
  • have you included the first project with step definitions in the build path of the second project with the main class. – Grasshopper Nov 25 '17 at 15:55
  • Yes, i tried that as well. Both projs are in diff eclipse instance but that shouldn't matter i guess. Also in case of dedault package, what should u specify for -g option – user578219 Nov 25 '17 at 21:32
  • For default package I think it should pick the stepdefs automatically. One way to figure out what is missing is to use the runner in the same project as the stepdefs and check. Another thing to try is to create a jar file for the project with stepdefs and importing it to second project. – Grasshopper Nov 26 '17 at 11:02
  • Have you tried to amend the option for the glue classes as shown in the example of my answer? Did it solve your problem? – SubOptimal Nov 28 '17 at 10:25
  • Thanks for the answer. I works in a normal project now. – user578219 Nov 29 '17 at 06:04
  • Another issue: I have some old projects that need to integrate with cucumber. All the .class and .java are present in the folder(NO src or bin): C:\work\RFT_WS2\Cuketest3. I have this directory in the Classpath. I have tried following option but unable to understand: -g "" path/to/feature then tried adding "C:\work\RFT_WS2" to classpath and -g "Cuketest3" But if I keep "C:\work\RFT_WS2\Cuketest3" in classpath an add the .java in a package and pass that package to glue. it works. So in may case for default package, its unable to find the .class(asks me to implement the methods) – user578219 Nov 29 '17 at 06:11
  • Also How do I specify multiple packages in -g option. Separating by ";", "," or "" doesn't work – user578219 Nov 29 '17 at 07:09
  • Either add this request into your original question or create a new one. Short answer. **1)** Use `java -cp .:other_dirs ...` and `"--glue", "", {other options}` **2)** `"--glue", "first/package", "second/package/", {other options}` – SubOptimal Nov 29 '17 at 09:17
  • @SubOptimal, Thanks. It doesn't work. Tried only the second option. – user578219 Nov 29 '17 at 11:09
  • Have a look to my answer. I added an example for `Using Step definitions in default package` and `Using Step definitions from different packages.`. – SubOptimal Nov 30 '17 at 07:39
  • Thanks, It worked. I need to find issue in my case as I am passing my own ClassLoader. Thanks a lot. – user578219 Dec 02 '17 at 07:15

2 Answers2

6

The glue option takes a path value which reflects the package(s) of the glue classes to be included in the classpath.

Find a simplified working example below

Assume following structure

/tmp/cuke-test/features/cukefeature.feature
/tmp/cuke-test/lib
/tmp/cuke-test/project1/src/com/cuke/CukeSteps.java
/tmp/cuke-test/project2/src/UseCukeFromMain.java

cukefeature.feature

Feature: simple test
  Scenario: test programatic call of Cucumber
  Given we have feature file
  When some glue code exists
  Then those steps should not fail

lib

cucumber-core-2.1.0.jar
cucumber-html-0.2.6.jar
cucumber-java-2.1.0.jar
cucumber-jvm-deps-1.0.6.jar
cucumber-testng-2.1.0.jar
gherkin-5.0.0.jar
jcommander-1.64.jar
snakeyaml-1.17.jar
tag-expressions-1.0.1.jar
testng-6.11.jar

CukeSteps.java

package com.cuke;

import cucumber.api.PendingException;
import cucumber.api.Scenario;
import cucumber.api.java.Before;
import cucumber.api.java.en.*;

public class CukeSteps {
    @Given("^we have feature file$")
    public void we_have_feature_file() throws Throwable {
        System.out.println("execute Given step");
    }

    @When("^some glue code exists$")
    public void some_glue_code_exists() throws Throwable {
        System.out.println("execute Then step");
    }

    @Then("^those steps should not fail$")
    public void those_steps_should_not_fail() throws Throwable {
        throw new PendingException();
    }
}

UseCukeFromMain.java

import cucumber.api.cli.Main;

public class UseCukeFromMain {
    public static void main(String[] args) throws Throwable {
        Main.main(new String[]{
            "--glue",
            "com/cuke", // the package which contains the glue classes
            "/tmp/cuke-test/features/cukefeature.feature"}
        );
    }
}

compile the classes

javac -cp "lib/*" -d project1/bin/ project1/src/com/cuke/*.java
javac -cp "lib/*" -d project2/bin/ project2/src/*.java

run the UseCukeFromMain

The root direcotry which contains the glue classes (project1/bin) must be in the classpath.

java -cp "project2/bin:project1/bin:lib/*" UseCukeFromMain

output

execute Given step
execute Then step

1 Scenarios (1 pending)
3 Steps (1 pending, 2 passed)
0m0.104s

cucumber.api.PendingException: TODO: implement me
    at com.cuke.CukeSteps.those_steps_should_not_fail(CukeSteps.java:21)
    at ✽.those steps should not fail(/tmp/cuke-test/features/cukefeature.feature:6)

edit Using Step definitions in default package

Assume following structure

features/cukefeature.feature
lib/
project1/src/CukeSteps.java
project2/src/UseCukeFromMain.java

cukefeature.feature
lib/

the same as in the first example

CukeSteps.java

// note: there is no package statement

import cucumber.api.PendingException;
import cucumber.api.Scenario;
import cucumber.api.java.Before;
import cucumber.api.java.en.*;

public class CukeSteps {
    @Given("^we have feature file$")
    public void we_have_feature_file() throws Throwable {
        System.out.println("execute Given step");
    }

    @When("^some glue code exists$")
    public void some_glue_code_exists() throws Throwable {
        System.out.println("execute Then step");
    }

    @Then("^those steps should not fail$")
    public void those_steps_should_not_fail() throws Throwable {
        throw new PendingException();
    }
}

UseCukeFromMain.java

import cucumber.api.cli.Main;

public class UseCukeFromMain {
    public static void main(String[] args) throws Throwable {
        Main.main(new String[]{
            "--glue",
            "",  // to used Step definitions in default package
            "features/cukefeature.feature"}
        );
    }
}

compile classes

The option -d . creates the class files in the current directory.

javac -cp "lib/*" -d . project1/src/*.java
javac -cp "lib/*" -d project2/bin/ project2/src/*.java

created class files

CukeSteps.class
project2/bin/UseCukeFromMain.class

run the UseCukeFromMain

The current directory is added to the classpath using the ..

java -cp "project2/bin:.:lib/*" UseCukeFromMain

output

execute Given step - default package
execute Then step - default package

1 Scenarios (1 pending)
3 Steps (1 pending, 2 passed)
0m0.096s

cucumber.api.PendingException: TODO: implement me
    at CukeSteps.those_steps_should_not_fail(CukeSteps.java:19)
    at ✽.those steps should not fail(features/cukefeature.feature:5)

edit Using Step definitions from different packages.

Assume following structure

features/cukefeature.feature
lib
project1/src/com/cuke1/CukeStepsB.java
project1/src/com/cuke/CukeStepsA.java
project2/src/UseCukeFromMain.java

cukefeature.feature
lib/

the same as in the first example

The Step definitions are split in two classes, in different packages

CukeStepsA.java

package com.cuke;

import cucumber.api.PendingException;
import cucumber.api.Scenario;
import cucumber.api.java.Before;
import cucumber.api.java.en.*;

public class CukeStepsA {
    @Given("^we have feature file$")
    public void we_have_feature_file() throws Throwable {
        System.out.println("execute Given step - package com.cuke");
    }
}

CukeStepsB.java

package com.cuke1;

import cucumber.api.PendingException;
import cucumber.api.Scenario;
import cucumber.api.java.Before;
import cucumber.api.java.en.*;

public class CukeStepsB {
    @When("^some glue code exists$")
    public void some_glue_code_exists() throws Throwable {
        System.out.println("execute Then step - package com.cuke1");
    }

    @Then("^those steps should not fail$")
    public void those_steps_should_not_fail() throws Throwable {
        throw new PendingException();
    }
}

UseCukeFromMain.java

import cucumber.api.cli.Main;

public class UseCukeFromMain {
    public static void main(String[] args) throws Throwable {
        Main.main(new String[]{
            "--glue",
            "com/cuke",
            "--glue",
            "com/cuke1",
            "features/cukefeature.feature"}
        );
    }
}

compile classes

javac -cp "lib/*" -d project1/bin/ project1/src/com/cuke/*.java project1/src/com/cuke1/*.java
javac -cp "lib/*" -d project2/bin/ project2/src/*.java

created class files

project1/bin/com/cuke1/CukeStepsB.class
project1/bin/com/cuke/CukeStepsA.class
project2/bin/UseCukeFromMain.class

run the UseCukeFromMain

java -cp "project2/bin:project1/bin:lib/*" UseCukeFromMain

output

execute Given step - package com.cuke
execute Then step - package com.cuke1

1 Scenarios (1 pending)
3 Steps (1 pending, 2 passed)
0m0.114s

cucumber.api.PendingException: TODO: implement me
    at com.cuke1.CukeStepsB.those_steps_should_not_fail(CukeStepsB.java:16)
    at ✽.those steps should not fail(features/cukefeature.feature:5)
SubOptimal
  • 22,518
  • 3
  • 53
  • 69
  • Thanks for your comment. Could you please see my comment to the question for another issue. – user578219 Nov 29 '17 at 06:12
  • Blank String ("") works like all packages. So if I would like to include default package and com.cuke, how would that be. Using below options are not fine. "--glue", ",com.cuke", or " ,com.cuke" – user578219 Dec 10 '17 at 10:05
  • Also putting 2 packages to --glue like "steps,steps1" doesnot work. But giving 2 --glue options like "--glue", "steps", "--glue", "steps1" works fine – user578219 Dec 10 '17 at 10:10
  • Can you also help me get put all these options when we run cucumber uding command prompt. I am getting little confused since Main.run() takes a Sting[ ] but when its passed through command prompt its String. How to take care of options like "--tags" whose value take options separated by ", like "@sanity, @smoke". I need to have this as I am integrating all these with our existing commandline options – user578219 Dec 10 '17 at 10:56
  • **1)** `"--glue", "" works like all packages`, yes as "--glue" starts from the mentioned point and include all sibllings, see the default package like as root off all packages, **2)** `"--glue", "steps", "--glue", "steps1" works fine` - that's what I showed in my answer, **3)** please start a new question for it, as it's not anymore related to your initial question. – SubOptimal Dec 11 '17 at 13:44
3

The absolute path is required for feature file. The step def directory requires classpath format.

   public static void main(String[] args) throws Throwable {

           //Your code to get feature file full path        

            Main.main(new String[]{"-g", "classpath to step definition file", "Full path to feature file"});    
        }
Manmohan_singh
  • 1,776
  • 3
  • 20
  • 29