Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running Cucumber tests directly from executable jar

I have a project with cucumber and maven also I am using the JUnit.

I am able to run and build my project successfully from Eclipse.

Now I want to run the test from command line in another system which does(should) not have eclipse or cucumber installed. I have an idea that we can create a JAR from jar we can run the tests by java cli commands.

Below are the combinations I am trying to run my tests from , also I am pasting the pom.xml and RunCukesTest.java file..

enter image description here

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>pmc</groupId>
    <artifactId>se</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>storeEnabler</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>1.2.0</version>
        </dependency>

        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-testng</artifactId>
            <version>1.2.0</version>
        </dependency>

        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-junit</artifactId>
            <version>1.2.4</version>
        </dependency>

        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>2.52.0</version>
        </dependency>

        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>1.4</version>
        </dependency>

        <dependency>
            <groupId>io.appium</groupId>
            <artifactId>java-client</artifactId>
            <version>3.1.0</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.9</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.11-beta3</version>
        </dependency>

        <dependency>
            <groupId>xml-apis</groupId>
            <artifactId>xml-apis</artifactId>
            <version>2.0.2</version>
        </dependency>

        <dependency>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
            <version>2.8.0</version>
        </dependency>
    </dependencies>

    <build>
        <testResources>
            <testResource>
                <directory>${project.basedir}/src/test/java</directory>
            </testResource>
            <testResource>
                <directory>${project.basedir}/src/test/resource</directory>
            </testResource>
        </testResources>
        <pluginManagement>
            <plugins>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.1</version>
                    <configuration>
                        <fork>true</fork>
                        <executable>C:\Program Files\Java\jdk1.8.0_60\bin\javac.exe</executable>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.18</version>
                    <dependencies>
                        <dependency>
                            <groupId>org.apache.maven.surefire</groupId>
                            <artifactId>surefire-junit47</artifactId>
                            <version>2.18</version>
                        </dependency>
                    </dependencies>
                </plugin>
                    <plugin>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <configuration>
                        <archive>
                            <manifest>
                            <addClasspath>true</addClasspath>
                                <mainClass>cucumber.api.cli.Main</mainClass>
                            </manifest>
                        </archive>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

RunCukesTest.java

package se.stepDefinations;


import org.junit.runner.RunWith;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
@CucumberOptions(features = "src/test/resource/features/Printing.feature:117", plugin = { "pretty",
        "html:target/cucumber-html-report" }, glue = { "se.stepDefinations" }, tags = {})
public class RunCukesTest {

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


    }
}
  • I have added JUNIT Jar in Class path.

I am generating jars in 2 ways,

1) Exporting JAR using - > Project ->Export -> JAR File Selecting MAIN Class in the last step as : RunCukesTest as I have defined main method here for the entry point(do we require this main method in this class???)

After the export , I am running below command ,

1.1 java -jar xyz.jar I get error : NoClassDef found : org/junit/runner/JUnitCore

So I ran it this way :

1.2 java -cp xyz.jar;junit-4.12.jar org.junit.runner.JUnitCore It said,

JUnit version 4.12
Time:0.001
OK(0 tests) 

It still didnt work , So I appended the RunCukesTest file namespace at the last,
1.3 java -cp xyz.jar;junit-4.12.jar org.junit.runner.JUnitCore se.stepDefinations.RunCukesTest
It gave me error :Type cucumber.api.junit.Cucumber not present

2) So I gave up on the option for Export of jar and I am trying now to use the JAR from the maven Build. I selected the POM to run with Maven Build and it created 2 jars in the target folder ,

1 with name xyz-0.0.1-SNAPSHOT with 16kb another with 2nd with
xyz-0.0.1-SNAPSHOT-jar-with-dependencies with 33mb

1) I ran the bigger file with dependencies using

java -jar xyz-0.0.1-SNAPSHOT-jar-with-dependencies.jar

It gave me message :

Got no path to feature directory

2) So I tried appending the namespace to RunCukesTest file,

java -jar xyz-0.0.1-SNAPSHOT-jar-with-dependencies.jar se.stepDefinations.RunCukesTest

I received an error : not a file or directory found

, as of course as the error says , it is trying to find a feature inside the target folder.

Again , I want to run the JAR independent of any such project file dependencies in any other computer like an executable.

Any help would be appreciated. Thanks.

like image 366
Arpan Buch Avatar asked Mar 22 '16 08:03

Arpan Buch


People also ask

Can we run Cucumber without JUnit?

Cucumber is just another custom Junit runner. so can not have cucumber without Junit.


2 Answers

I would divide the problem you are thinking of in two parts.

  • Create an executable jar
  • Run Cucumber from your own main method

Creating an executable jar using Maven can be done in different ways. One way of doing it is described here: http://www.thinkcode.se/blog/2011/03/05/create-an-executable-jar-from-maven

It is a small example that only focuses on executing something from a command line like this:

java -jar executable-example.jar

The example contains all dependencies. They are all bundled in the same jar. No need for any additional jars.

Next step would be to execute Cucumber from a main method. My approach would be to write a main that executes the Cucumber main method used for the command line version of Cucumber. The main method used to run cucumber from a command line lives in the cucumber-java library. You will find it at cucumber.api.cli.Main

Running a main method from another main method is done like this:

public static void main(String[] args) throws Throwable {
    String[] arguments = {"foo", "bar"};
    cucumber.api.cli.Main.main(arguments);
}

where arguments are the command line arguments you always want to execute Cucumber with.

Given these two steps, you should be able to execute Cucumber from your own executable jar wherever you are able to execute a jar at all.

Notice that you are mixing library version for Cucumber in your pom. I would use the latest version of all libraries. Compare cucumber-java, cucumber-testng and cucumber-junit. The latest Cucumber version is 1.2.4. I would use it for all of them.

More information about running Cucumber from a command line can be found here: https://cucumber.io/docs/cucumber/api/#from-the-command-line

like image 69
Thomas Sundberg Avatar answered Sep 18 '22 07:09

Thomas Sundberg


I'd like to extend the accepted answer to support Gradle, since this might be helpful for someone.

Given this is your project's structure

  • .root
    • src/
      • main/
        • java/ --> Put your .java files here
          • CukesRunner.java --> This is your main file
        • resources
          • features/ --> Put your .feature files here

The build.gradle file should look like something like this:


    apply plugin: 'java'
    
    sourceSets {
        main {
            java {
                srcDirs = ['src/main/java']
            }
            resources {
                srcDirs = ['src/main/resources']
            }
        }
    }
    
    dependencies {
         // Include your dependencies here
         compile '...'
     }
    
    configurations {
        cucumberRuntime {
            extendsFrom compile
        }
    }
    
    jar {
        from {
            // Package all dependencies in the .jar
            configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
        }
        manifest {
            // Indicate the main class for the .jar file
            attributes 'Main-Class': 'CukesRunner'
        }
    }

Then you can customize your CukesRunner.java just like the accepted answer suggested, but making sure to call for the features you compressed together with your jar file:

public class CukesRunner {
    
    public static void main(String[] args) throws Throwable {
        final String[] arguments = new String[]{
                "--glue", "<my Java classes packages reference>",
                "classpath:features" // This will look for the classpath inside the jar file
        };
        cucumber.api.cli.Main.main(arguments);
    }

}
like image 41
Rodrigo Novaes Avatar answered Sep 17 '22 07:09

Rodrigo Novaes