Search code examples
javacucumberbddcucumber-jvmcucumber-java

Running Cucumber project using Main.run from another main method


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.


Solution

  • 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)