Run tests from a #Category using Maven - java

I have looked at a few other SO questions like this and this. But those questions are pretty dated and I'm curious if there exists a new solution.
Here's what my setup looks like:
Category interface:
public interface FastTest{}
Category suite:
#RunWith(Categories.class)
#IncludeCategory(FastTest.class)
public class FastSuite{}
Sample test:
#Category(FastTest.class)
public class FastTests{
#Test public void assertOneFastTest(){}
#Test public void assertTwoFastTest(){}
}
Using maven, let's say I want to only run all my FastTest tests. Ideally, I would use the command
mvn test -Dtest.category=FastTest
or
mvn test -Dtest.suite=FastSuite
But I have not been able to get this working. Does anyone have any suggestions aside from using ClasspathSuite? Thanks.

You can do this from the surefire plugin, using the configuration for groups, but you need to specify the junit47 provider as well. The following works for me:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.11</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.11</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>default-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<groups>com.xxx.foo.CategoryClass</groups>
</configuration>
</plugin>
I think this was introduced fairly recently, so may not work in earlier versions of the plugin, pre 2.11. You need to specify the provider, otherwise it doesn't work. The groups should be the fully qualified name of the Category class. You can also specify an excludeGroups as well if needs be.
For more information, see Maven Surefire Plugin surefire:test.

Did a little more research and found no options so I ended up using ClasspathSuite. It turns out that it's not any different except that you cannot specify #Category at a class level, you have to annotate every method you want to categorize
Now, each category suite looks like this:
#RunWith(Categories.class)
#Categories.IncludeCategory(FastTest.class)
#Suite.SuiteClasses(AllTests.class)
public class FastSuite{}
You have to modify AllTests to look like this:
#RunWith(ClasspathSuite.class)
public class AllTests{}
For methods, it looks like this:
public class FastTests{
#Categories(FastTest.class)
public void assertOneFastTest(){}
#Categories(FastTest.class)
public void assertTwoFastTest(){}
}
Using maven, you can do the following command:
mvn test -Dtest=FastSuite -Dt3-chrome-path=%CHROME_DRIVER_HOME -Dwebdriver.chrome.driver=%CHROME_DRIVER_HOME

Related

Junit5 Tag Annotation together with Quarkus QuarkusTestResource Annotation

How can QuarkusTestResource be used in conjunction with Tag Annotation?
Example Test Routine
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
#QuarkusTest
#Tag("integration")
#QuarkusTestResource(DatabaseResource.class)
public class MyTest {
#Test
public void () {
doTests...
}
}
Maven Snippet:
<quarkus-plugin.version>1.12.1.Final</quarkus-plugin.version>
<quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>1.12.1.Final</quarkus.platform.version>
<surefire-plugin.version>2.22.1</surefire-plugin.version>
<testscope>unit</testscope>
...
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<groups>${testscope}</groups>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
...
Maven Command:
./mvnw clean test
Result: QuarkusTestResource are started even if no QuarkusTest is annotated with "unit", so it seems that Quarkus is not aware of the Tag Annotation?
Quarkus Test Resources are global which means it will run anyway, even if your class is annotated with a tag that shouldn't run.
To prevent this, try annotating your class with
#QuarkusTestResource(restrictToAnnotatedClass = true)
From the Quarkus' website
test resources are global, even if they are defined on a test class or custom profile, which means they will all be activated for all tests, even though we do remove duplicates. If you want to only enable a test resource on a single test class or test profile, you can use #QuarkusTestResource(restrictToAnnotatedClass = true).
What you are looking for is likely the tags methof of QuarkusTestProfile. See this part of the documentation

Javadoc "cannot find symbol" error when using Lombok's #Builder annotation

I have a class looking as below :
#Data
#Builder
public class Foo {
private String param;
/** My custom builder.*/
public static FooBuilder builder(String _param){
return builder().param(_param);
}
}
I get the following error :
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:2.10.4:javadoc (default-cli) on project foo: An error has occurred in JavaDocs report generation:
[ERROR] Exit code: 1 - /home/workspace/foo/src/main/java/com/foo/Foo.java:34: error: cannot find symbol
[ERROR] public static FooBuilder builder(String _param)
[ERROR] ^
[ERROR] symbol: class FooBuilder
[ERROR] location: class Foo
Lombok is actually capable of filling out a partially defined builder class, so you can declare enough of the builder to make Javadoc happy and leave it at that. No need to delombok.
The following worked for me in this situation:
#Data
#Builder
public class Foo {
private String param;
// Add this line and all is good
public static class FooBuilder {}
}
Side note: that you can actually use this technique to add some customer builder methods, so it has perks. I like to overload builder methods when I have collections so I can items one at a time. There's probably already some technique that does that, but it's nice to know you can improve the builders manually.
Here's a common thing I like to do:
#Builder
public class Foo {
private final String command;
private final List<String> params;
private final boolean background;
public static class FooBuilder {
public FooBuilder params(final String... params) {
this.params = Arrays.asList(params);
return this;
}
}
}
In the above the params builder method has been customized to take var args. The other builder method will still be created by Lombok.
In order to solve this issue, I have to use Lombok's delombok feature (cf : https://projectlombok.org/features/delombok).
lombok doesn't cover all tools. For example, lombok cannot plug into javadoc ... which run on java sources. Delombok still allows you to use lombok with these tools by preprocessing your java code into java code with all of lombok's transformations already applied.
I did this using Maven by adding the following plugins :
<plugin>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-maven-plugin</artifactId>
<version>1.18.0.0</version>
<configuration>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<outputDirectory>${delombok.output}</outputDirectory>
<addOutputDirectory>false</addOutputDirectory>
</configuration>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>delombok</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<configuration>
<sourcepath>${delombok.output}</sourcepath>
</configuration>
</plugin>
Update
If you use maven-javadoc-plugin 3.2.0+ you can configure it like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<doclint>none</doclint>
</configuration>
</plugin>
The doclint configuration will make javadoc plugin not throw an error anymore. It will also disable the lint but if you are ok with this probably the best way to go instead of delombok.
If you use any CI tool to build and compile your project you can create a separated job to check for javadoc lint.
For me disabling lint in the build is not a bad thing. Javadoc is important but shouldn't keep me from building my application just because I'm using Lombok.
Another solution to this would be to not include the BuilderClass in your imports. Instead just import the parent class and change your declaration of the builder type to parentClass.builderClass.
#Getter
#RequiredArgsConstructor
#Builder
public class Foo {
private final String param;
}
import com.Foo;
//import com.Foo.FooBuilder;
public class Bar {
public Foo newFoo(String paramValue) {
Foo.FooBuilder builder = Foo.builder();
return builder.param(paramValue)
.build();
}
}

JUnit 4 - How to ignore all package with the tests?

I run my JUnit and Mockito tests in a big project. I use them for testing my server-side components that connect to web-service. All these connections require some time and it is not neccessary for them to be executed during the build.
I would like that my tests would be ignored during the build.
I have about 10 classes with tests. So the obvious way is to annotate all the classes with #Ignore. However I should do this every time I commit my code to the project and then re-annotate all tests. Not the very best solution I think.
So is this possible somehow simply ignore all package (let say com.example.tests) with the tests?
Or what might be the solution to ignore tests in the build in a simple way?
You can mention on your build.gradle what packages to exclude from tests
test {
exclude '**/*IntegrationTest*'
}
same for maven:
must consider this notation:
By default, the Surefire Plugin will automatically include all test classes with the following wildcard patterns:
"**/Test*.java" - includes all of its subdirectories and all Java filenames that start with "Test".
"**/*Test.java" - includes all of its subdirectories and all Java filenames that end with "Test".
"**/*Tests.java" - includes all of its subdirectories and all Java filenames that end with "Tests".
"**/*TestCase.java" - includes all of its subdirectories and all Java filenames that end with "TestCase".
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<excludes>
<exclude>*com.example.tests*/*Test.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
[...]
</project>
Another option is the old
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
or even when call it
mvn install -DskipTests
Using Categories seems to be an option that can come in handy
This is how you may add these to your Gradle script.
test {
useJUnit {
includeCategories 'org.gradle.junit.CategoryA'
excludeCategories 'org.gradle.junit.CategoryB'
}
}
A sample can be found here, adding it for a quick reference.
public interface FastTests
{
/* category marker */
}
public interface SlowTests
{
/* category marker */
}
public class A
{
#Category(SlowTests.class)
#Test public void a()
{
}
}
#Category(FastTests.class})
public class B
{
#Test public void b()
{
}
}
#RunWith(Categories.class)
#IncludeCategory(SlowTests.class)
#ExcludeCategory(FastTests.class)
#SuiteClasses({ A.class, B.class })
public class SlowTestSuite
{
}
I have found the solution for my case.
To disable all the tests during the build or even in any other context that you want the Spring annotation #IfProfileValue can be used. All tests with this annotation will be executed only in wanted context.
The example is this:
#IfProfileValue(name="enableTests", value="true")
public class DemoApplicationTests {
#Test
public void contextLoads() {
...
}
}
In my IDE I can edit the configuration and set the variable by:
-DenableTests=true
This annotation can be used on the level of a class or on the level of a test also.
All classes or tests annotated with such #IfProfileValue will be executed only in my environment and will be ignored during the build.
This approach is the best for me because it is not convenient in my project to change main pom.xml for my own test needs.
Addition.
Also in Spring or Spring Boot you should add Runner.
For example in Spring:
#RunWith(SpringJUnit4ClassRunner.class)
#IfProfileValue(name="enableTests", value="true")
#ContextConfiguration(classes = { YourClassConfig.class })
YourClassConfig might be empty:
#Configuration
public class YourClassConfig {
}

Version information for Java library, accessible at runtime

For supporting purposes I need to add a version and build identifier to our Java library. The library itself is a toolkit without user interaction which is used in different environments (stand alone Java applications, web applications, Eclipse applications, Maven dependency, ...).
What I want, is a class with some constants giving me the above described information (such as MyAppVersion.BUILD, ...), so that they can be shown e.g. in dialogs, command line output, etc. After my research, there seem to be the following approaches:
add versioning to file name, such as myLibrary-0.1.2.jar; not feasible in our case, since I have no control over the file name when deployed
add information to the MANIFEST.MF and read it programmatically, like described here. I'm not sure however, how robust this approach is in respect to different class loaders (Eclipse, OSGi, application servers, ...) and if the JAR file gets re-packaged, this information is lost
use a version.properties file holding the version, as described here and use a script during build to update the version.properties file
hard code the version information into the class directly and use a script to update this information
Are there any other approaches? The last option seems most "robust" to me, are there any objections against this variant? Is there a Maven plugin which would support updating this information in a MyAppVersion.java file during build?
I would suggest to use the templating-maven-plugin which is created exactly for such purposes.
You create at best a separate module which contains a template class like this (or within your module):
public final class Version {
private static final String VERSION = "${project.version}";
private static final String GROUPID = "${project.groupId}";
private static final String SVN = "${project.scm.developerConnection}";
private static final String SVN_BRANCH = "${scmBranch}";
private static final String REVISION = "${buildNumber}";
public static String getVersion() {
return VERSION;
}
public static String getGroupId() {
return GROUPID;
}
public static String getSVN() {
return SVN;
}
public static String getRevision() {
return REVISION;
}
public static String getSVNBranch() {
return SVN_BRANCH;
}
}
Which you simply put into src/main/java-templates folder plus an appropriate package name. Furthermore you configure the templating-maven-plugin like the following in your pom file:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
<version>1.0-alpha-3</version>
<executions>
<execution>
<goals>
<goal>filter-sources</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
This will generate a class Version which can be used by others and contains the given version. In the above template class you can use any property which is available in your build (things like JENKINS_ID etc.) or things your might define by yourself.
The result is that this class is compiled and packaged into your jar file.
Apart from that you can combine that with the buildnumber-maven-plugin to create the buildNumber which needs to be added to your pom file like this:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.2</version>
<configuration>
<revisionOnScmFailure>UNKNOWN</revisionOnScmFailure>
<getRevisionOnlyOnce>true</getRevisionOnlyOnce>
</configuration>
<executions>
<execution>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
</plugin>
The last option of hardcoding the version is the most robust which seems to be important to you.
If you build using ant, you can write a class (let's call it VersionGenerator) that will generate a java file with version:
package my.cool.package;
public interface Version {
String VERSION = "1.2.3";
}
Call VersionGenerator from ant
And then compile all your code and roll it into a jar. And your jar will contain a freshly generated and compiled Version.class!
VersionGenerator will have the logic of how to name and increase versions

Run tests from inner classes via Maven

I have following tests structure:
public class WorkerServiceTest {
public class RaiseErrorTest extends AbstractDbUnitTest{
#Test
public void testSomething(){
}
...
}
...
}
It's done because I don't want to create a separate class file for every test case extending AbstractDbUnitTest.
The problem is that mvn test doesn't run test from my inner class. Is there is a way how to configure Maven to run such tests? Of course I can create methods in the parent class calling the inner class methods but I want a clearer way.
Yes, this is possible using the new (well, it's not new anymore) Enclosed runner (since JUnit 4.5) that runs all static inner classes of an outer class.
To use it, just annotate the outer class with #RunWith(Enclosed.class) and make the inner classes static.
#RunWith(Enclosed.class)
public class WorkerServiceTest {
public static class RaiseErrorTest extends AbstractDbUnitTest{
#Test
public void testSomething(){
}
...
}
...
}
And mvn test will run them.
I explain (a little more) the solution that I found...
Maven (AFAIK) uses by default the plugin "maven-surefire-plugin" to run any tests defined at your maven project. According to the documentation of this plugin, by default, it excludes tests that are enclosed at inner static classes (or at least it was with version that i'm using - 2.18.1).
So what i did was to put a empty exclude rule; resulting with a pom's build section like this:
<build>
<plugins>
...
<!-- ~~~~~~~~~~ SUREFIRE -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<excludes>
<exclude></exclude>
</excludes>
</configuration>
</plugin>
...
</plugins>
</build>

Categories

Resources