Skip to content

Packaging a test in an executable JAR file

One of the most common points of discussion when starting the development of a test automation project is how will the tests be distributed and executed. When working with Java, an executable JAR file could be a good option to solve this. The benefits of taking this approach are:

· Tests can be easily distributed among teams by just sharing a single JAR file.
· Code is protected from any intended or unintended modification that could impact the accuracy of the test results.
· Tests can be executed with less required setup. There is no need for an IDE (Integrated Development Environment), version control system and JDK (Java Development Kit), to be able to pull code, compile and run the tests. Having JRE (Java Runtime Environment) properly configured should be enough.

The challenge here is to pack a “stand-alone” Java test in an executable jar without losing other execution options for the test, like MVN test and execution from IDE.

Assumptions

We are dealing with a “stand-alone” test, meaning we don’t have a main source code to test in the same project. Instead, the test source code contains all that is required to execute the test. A common scenario is a UI functional testing of a web app using Selenium, where we just need access to the app through a URL, and all the page classes and tests are contained in a single source of code.

Also, this implementation assumes maven keeps the default directory structure:

src/main/java
src/main/resources
src/test/java
src/test/resources

There are two approaches that can be used:

A. Test code is in “main”

  1. The test code and resources are contained in (or moved to) the main module src/main/java and src/main/resources
  2. Create a Main class where you can start the execution from. Example:
    
    public class TestMainRunner {
        public static void main(String[] args) {
    
            String[] cucumberArgs = new String[] {
                    "-g","steps",
                    "classpath:features",
                    "-p", "pretty"
            };
    
            Main.run(cucumberArgs);
        }
    }
    
  3. Add maven-assembly-plugin to pom.xml to enable creating a .jar file including the project dependencies and also to specify the main class to be executed when running the .jar:

    
    <build>
    <plugins>
    ...
    	<plugin>
    	    <artifactId>maven-assembly-plugin</artifactId>
    	    <executions>
    	        <execution>
    	            <phase>package
    	            <goals>
    	                <goal>single
    	            </goals>
    	        </execution>
    	    </executions>
    	    <configuration>
    	        <archive>
    	            <manifest>
    	                <addClasspath>true</addClasspath>
    	                <mainClass>run.TestMainRunner</mainClass>
    	            </manifest>
    	        </archive>
    	        <descriptorRefs>
    	            <descriptorRef>jar-with-dependencies</descriptorRef>
    	        </descriptorRefs>
    	    </configuration>
    	</plugin>
    ...
    </build>
    </plugins>
    

    To generate the .jar file run from terminal:
    mvn clean compile assembly:single

    jar file is output to target

    folder

  4. Define src/main/java and src/main/resources as test source and resources in the pom.xml:

    
    <build>
    ...
    	<testSourceDirectory>
    	    src/main/java
    	</testSourceDirectory>
    	
    	<testResources>
    	    <testResource>
    	        <directory>src/main/resources</directory>
    	    </testResource>
    	</testResources>
    ...
    </build>
    

    By doing this, test can be executed by running from the terminal:

    mvn test
    Note: When executing mvn test, test-classes folder is generated in target with same content as classes. That might cause some warning during execution, nothing to worry about.

B. Test code is in “test”

In case tests are developed under test module and there is not option to move them to main, this could one helpful approach.

  1. The test code and resources are contained in (or moved to) the test module src/test/java and src/test/resources
  2. Create a Main class where you can start the execution from. Example:

    
    public class TestMainRunner {
        public static void main(String[] args) {
    
            String[] cucumberArgs = new String[] {
                    "-g","steps",
                    "classpath:features",
                    "-p", "pretty"
            };
    
            Main.run(cucumberArgs);
        }
    }
    
  3. Add maven-assembly-plugin to pom.xml to enable creating a .jar file including the project dependencies and also to specify the main class to be executed when running the .jar:

    
    <build>
    <plugins>
    ...
    	<plugin>
    	    <artifactId>maven-assembly-plugin</artifactId>
    	    <executions>
    	        <execution>
    	            <phase>package</phase>
    	            <goals>
    	                <goal>single</goal>
    	            </goals>
    	        </execution>
    	    </executions>
    	    <configuration>
    	        <archive>
    	            <manifest>
    	                <addClasspath>true</addClasspath>
    	                <mainClass>run.TestMainRunner</mainClass>
    	            </manifest>
    	        </archive>
    	        <descriptorRefs>
    	            <descriptorRef>jar-with-dependencies</descriptorRef>
    	        </descriptorRefs>
    	    </configuration>
    	</plugin>
    ...
    </build>
    </plugins>
    
    
    To generate the .jar file run from terminal:
    mvn clean compile assembly:single
    jar file is output to target folder
    
  4. mvn test can be executed without any modification to the pom.xml file, since tests are contained in the default directory defined by maven.
  5. A last tweak required to execute the tests from the IDE (▶️), is to specify the resources directory in the pom.xml:
    
    <build>
    ...
        <!-- Required to execute from IDE when running feature directly -->
        <resources>
            <resource>
                <directory>src/test/resources</directory>
            </resource>
        </resources>
    ...
    </build>
    
Review the full implementation of this approach on a cucumber-junit template:

Salvador Jiménez Noriega

Software Quality Assurance Test Engineer
QA and Testing Engineer professional with over 10 years of experience across industries from manufacturing to software development. Most of my experience is in the definition and execution of quality and testing strategies including test automation, especially with JavaScript, Python and Java.