Run JUnit tests of a Maven Project in a specified order - java

I am working on a project to prioritize Junit tests based on their statement coverage for any Maven project (I am picking random projects from Git). So far I am able to get a list of the prioritized tests.
I am not sure how to make the Maven project run the tests in the sequence that I have come up with.
I did some search and found that Maven surefire plugin supports order using the runOrder tag. But the order is fixed - alphabetical/ reverse etc. I also came across TestNG which supports order specified on an XML file.
I cannot modify the source code in the target project( Since the source code is not written by me). I can only add new config files if needed or edit the POM.xml.
How can I achieve this? I would really appreciate if you could please direct me any resource useful to achieve this.
TIA

You can create and use JUnitTestSuite for this.
#RunWith(Suite.class)
#SuiteClasses({Test1.class,
Test2.class
})
public class YourTestSuite {
}
Test suite runs test cases in order in which they are mentioned in #SuiteClasses annotation.
And if you want to run test cases in order through maven goal like maven test goal, you can use this test suite. Just exclude test cases and include test case through plugin configuration given below.
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.6</version>
<configuration>
<excludes>
<exclude>**/*Test.java</exclude>
</excludes>
<includes>
<include>**/*TestSuite.java</include>
</includes>
<additionalClasspathElements>
<additionalClasspathElement>${project.build.sourceDirectory}</additionalClasspathElement>
<additionalClasspathElement>${project.build.testSourceDirectory}</additionalClasspathElement>
</additionalClasspathElements>
<useManifestOnlyJar>false</useManifestOnlyJar>
<forkMode>always</forkMode>
</configuration>
</plugin>

Related

How to run testng annotation based specific test suites with maven command line

In my project, tests are declared using annotations. For example:
#Slf4j
public class UnsecuredConnectionTest {
#Test(testName = "SM1570"
, suiteName = "connection")
public void TryUnsecurredConnectionTest() throws Exception {
//some logic
}
}
pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>${suiteXmlFile}</suiteXmlFile>
</suiteXmlFiles>
<skipTests>${skipTests}</skipTests>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
Also, the project does not have an xml file that would describe suites and tests with classes (like testng.xml or any other). For this reason, solutions from similar questions do not work
How do I tell Maven and TestNG to run either a specific test class or a suite.xml file?
Running Specific TestNG Suites with Maven via command line
TestNG surefire, run suite with maven command line
because surefire simply cannnot find xml file:
mvn test -DsuiteXmlFile=connection
Suite file C:\path\to\dir\connection is not a valid file
mvn test -DsuiteXmlFile=connection.xml
Suite file C:\path\to\dir\connection.xml is not a valid file
Is it possible to run tests via mvn test with common suiteName without adding xml files? And if the creation of xml files cannot be avoided, then how to combine information from annotations with them without duplicating the names of packages and classes?

Excluding tests from execution by PIT

I have to exclude my integration tests from their execution by PIT. There is an option excludedTestClasses since version 1.3.0. I tried to pass over these tests by the following configration of the Maven plugin of PIT.
<plugin>
<groupId>org.pitest</groupId>
<artifactId>pitest-maven</artifactId>
<version>1.3.1</version>
<configuration>
<verbose>true</verbose>
<mutationThreshold>80</mutationThreshold>
<targetClasses>
<param>de.comp.proj.*</param>
</targetClasses>
<excludedTestClasses>
<param>**/*IT.java</param>
</excludedTestClasses>
</configuration>
</plugin>
However PIT is still executing all tests with the suffix IT. I had a look the the source but got lost in the night ;-)
So, how can I skip my integration tests?
PIT filters are matched against the class names in the compiled binary, not against the source file name.
Your filter should look something like
<excludedTestClasses>
<param>de.comp.**.*IT</param>
</excludedTestClasses>
de.comp.*IT excludes all tests in the package de.comp. Using de.comp.**.*IT all tests in subpackages are also ignored.
For those using the Gradle plugin :
pitest {
excludedTestClasses = ['de.comp.**.*IT']
}
I use pitest-maven version 1.4.2.
This config works fine for me:
<excludedTestClasses>
<excludedTestClass>de.com.**.*IT</excludedTestClass>
</excludedTestClasses>
Maybe following syntax was for older versions of pitest-maven:
<excludedTestClasses>
<param>de.comp.**.*IT</param>
</excludedTestClasses>

Run tests only in test folder

I have a test project in java, that runs all tests found in the projects listed as dependencies for this project.
#RunWith(ClasspathSuite.class)
#ClassnameFilters({ "com.example.*_Test" })
public class AllRegularTests {
// nothing to do
}
My tests are usually in the test/ folder not in the src/
How can I make the test suite look only for classes in test/, and not in src/ ?
Maybe you can do it with the testSourceDirectory definition but I'm not sure.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testSourceDirectory>${basedir}/src/main/java/</testSourceDirectory>
<testClassesDirectory>${project.build.directory}/classes/</testClassesDirectory>
</configuration>
</plugin>
</plugins>
</build>
Few things seems to be wrong here :
By default Maven uses the following naming conventions when looking for tests to run: Test* *Test *TestCase Your test class doesn't follow these conventions. You should rename it or configure Maven Surefire Plugin to use another pattern for test classes.
unit test code should put under the test folder, it can not be recognized as test class if you put it under the main folder.
eg.
Wrong /my_program/src/main/java/NotTest.java
Right /my_program/src/test/java/MyTest.java
Also, check if your test classes directory (e.g. src/test/java) corresponds to directory listed in property in your pom.xml under property. Took me a while to find that.

Cucumber Step Definition from dependency jars

I have multiple projects using similar step definition across the different projects. Hence using all step definition in single project and added as dependency jar in maven.
When I run using maven command it says :
You can implement missing steps with the snippets below:
#When("^Import a canvas from \"(.*?)\" to project \"(.*?)\"$")
public void import_a_canvas_from_to_project(String arg1, String arg2) throws Throwable {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}
but when I add package in same project it works fine. (Even in eclipse from different projects works). Is there any way to run such scenarios from maven and jenkins?
I am using eclipse IDE. maven command I used is :
mvn -DprofileTest=cucumberID clean -P cucumberID test
cucumberID is my profile name.
Following profile I added in pom.xml
<profile>
<id>cucumberID</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<version>2.11</version>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
<includes>
<include>step_definitions/LoginTest.java</include>
</includes>
<parallel>classes</parallel>
<threadCount>3</threadCount>
<useFile>true</useFile>
</configuration>
</plugin>
</plugins>
</build>
</profile>
You haven't specified how are you running your test suite but assuming that you have #CucumberOptions somewhere, you can just point to other projects packages like this:
#CucumberOptions(. . . glue = {
"com.company.test.package1", "com.company2.test.package2", . . .})
use classpath: prefix for the package name to solve this.
for example:
#CucumberOptions(glue = { "classpath:com.example.test.steps" })
If you will use Maven's preferred way of creating packages, then "mvn package" your code, and "mvn install" this package, then you'll be able to run test from external library without changes in class annotated with #CucumberOptions.

How to run JUnit Test in maven if the test are not in test dir but in main dir and the classname are not having keywords like .*Test.*

Here is the back ground.
I was working on a project which was using ant build. When we use to create a new Class, we use to write the junit test in same class as ant supported it.The Class Name doesn't have 'Test' naming convention. There are more then 800 Junit tests.
Now we need to move to Maven build structure. Problem is that maven only runs junit where the class name has naming convention 'Test'.
How do i run the junit test which are in in src/main/java/* ?
Also, Is there a way where i can pull all methods that has '#Test' annotations?
Please let me know if you need any further info.
Just because you used to do it like that with Ant, doesn't make it right to keep using it now. Now that you've moved to Maven, you must comply with its way of doing things and follow its conventions. One of them is to keep your production code separate from your tests. A mixture does not make sense, as you are in fact littering your code with useless (for clients of your code) methods. While you can keep doing this and find workarounds, this is not the high-standard route to choose.
What you really need to do as a next step is schedule some refactoring time and carry out the following tasks:
Create src/test/java (and respectively -- src/test/resources).
Create a *Test class for each class that contains #Test annotated methods and place them under src/test/java.
Move those methods to the respective new classes.
Move all your resources that are only used by tests to your src/test/resources directory.
You have to change the configuration of the Surefire plugin, which runs the tests. I have not tested it, but you can try this configuration:
<build>
<testSourceDirectory>src/main/java</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<includes>
<include>**/*.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
I assume since you are using ant, you have a test suite? If so, the easiest way is to change the configuration to use the given test suite:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<includes>
<include>AllTest.class</include>
</includes>
</configuration>
</plugin>
However, I'm not sure if it will look in the src folder too so you may have to move the test suite to the test directory.
As for pulling all methods that have the #Test annotation (I assume without a suite?) you will have to do that yourself if you aren't following the sure-fire test class naming conventions. It isn't too hard to make your own test runner implementation that searches through all your classes in your class path or a sub-folder and finds all classes that meet your criteria and pass that to Junit to run.
If you are using eclipse, you can still execute it as Junit test.
In fact, if your "test classes" didn't put in the test folder, it means that you do not intend to run them as "test" at the maven build action.

Categories