Why doesn’t Maven execute my unit tests?

If you have been using Maven for some time, you might have noticed that Maven will automatically find and execute your unit tests when they are present in your project, even without any additional configuration.

This is because it is using the Surefire Plugin with a default configuration (that can be overridden of course). However, for this to execute your tests, you need to place your test classes in the proper place and you need to name them appropriately.

Location of test classes

Your test classes need to be placed under the src/test/java folder, otherwise it won’t be picked up.

Naming of test classes

By default, the Surefire Plugin will automatically include all test classes that where the name matches one of the following patterns:

  • Test*.java
  • *Test.java
  • *TestCase.java

Example

We have the following test classes:

And the result is:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.jtuts.MyTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.039 sec
Running com.jtuts.MyTestCase
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.002 sec
Running com.jtuts.TestMyCode
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 sec
Running com.jtuts.TestsForMyCode
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 sec

Results :

Tests run: 4, Failures: 0, Errors: 0, Skipped: 0

You can see that 3 of the above classes are skipped, because they do not match the naming convention.

Run embedded Tomcat 8 in Maven

The most common way to run your Java web app using Maven in an embedded container is the Tomcat Maven Plugin. However, the latest version of this plugin is for Tomcat 7 (last update released back in 2013).

Luckily there is another plugin that you can use, the Maven Cargo Plugin.

Here is an example working configuration that you can use with the plugin.

<plugin>
    <groupId>org.codehaus.cargo</groupId>
    <artifactId>cargo-maven2-plugin</artifactId>
    <configuration>
        <container>
            <containerId>tomcat8x</containerId>
            <artifactInstaller>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat</artifactId>
                <version>${tomcat.version}</version>
            </artifactInstaller>
        </container>
        <configuration>
            <type>standalone</type>
            <home>
                ${project.build.directory}/apache-tomcat-${tomcat.version}
            </home>
            <properties>
                <cargo.servlet.port>8080</cargo.servlet.port>
                <cargo.logging>high</cargo.logging>
            </properties>
        </configuration>
        <deployables>
            <deployable>
                <groupId>${project.groupId}</groupId>
                <artifactId>${project.artifactId}</artifactId>
                <type>war</type>
                <properties>
                    <context>/myapp</context>
                </properties>
            </deployable>
        </deployables>
    </configuration>
</plugin>

You can run your project using Cargo by using the cargo:run goal of the plugin. This will download the specified tomcat version and deploy your app into it.

Please note the ${tomcat.version} property, which you need to define in your pom.xml.

How to set up remote debugging in IntelliJ IDEA for a Java web application that is run by Tomcat Maven plugin

In this tutorial I show you a quick and easy way to debug your Java web application that is run by the Tomcat Maven plugin. There are just two short steps to this. Let’s see them.

Set up debugging options for Maven

You have to supply the required properties to Maven, so IDEA can connect to you app white it is running. This can be done by setting the MAVEN_OPTS environment property to

-Xdebug -Xrunjdwp:transport=dt_socket,address=4000,server=y,suspend=n -Xmx4g -Xms4g -XX:MaxPermSize=1g

Be sure to keep it in one line, I just broke it to two lines for readability.

Note here, the value 4000. This is the port that we are using for remove debugging. When you start your app with the Maven Tomcat plugin, you should see something like this, that means, the app is listening for remote debugging connections:

...
Listening for transport dt_socket at address: 4000
...

Configuring remote debugging in IDEA

For this you have to add a new Debug configuration that can be done by selecting the Run -> Edit configurations menu item. Here click the plus sign, to add a new configuration and select Remote.

The new Remote debugging configuration is immediately created. You can give it a name, and set the port to 4000. Here is an image about how I set it up:

remote-debugging-idea

 

After you configured it, click OK, select the created configuration and start debugging with the green button that resembles a bug.

remote-debugging-idea2

You are all set. You can add breakpoints and debug your running app remotely.

What’s with the -Xnoagent -Djava.compiler=NONE options?

You may see that in some places the remote debugging configuration contains the

-Xnoagent -Djava.compiler=NONE

options as well. These options were only required for very old JVMs so you can forget about them now.

 

How to list the effective settings of Maven

When you are using Maven, sometimes you need custom configuration in your Maven settings.xml file. However, if you are using multiple versions of Maven, or there are multiple settings.xml files existing at the same time, it can be hard to track down which settings file is actually used.

To help with this issue, there is the following command:

mvn help:effective-settings

It results in an XML displayed on the console. That XML contains the settings that are used by Maven.

 

Tomcat Maven plugin does not use the configured context path

When you use the Tomcat Maven Plugin to deploy your application, you can specify the context path under which you want your application to be accessible. An example of the configuration of this plugin looks like this:

<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
        <path>/jtuts</path>
    </configuration>
</plugin>

This way you application will be accessible under the /jtuts path. Depending on you port setting it can be for example localhost:8080/jtuts.

Sometimes you can run into an issue where no matter what you configure in the <path> element, you always end up with a context path that is equal to your artifactId. For example:

http://localhost:8080/using-spring-type-conversion-20140208

In my case the problem was the way I referenced the tomcat plugin in my mvn command. To use the Tomcat 7 plugin that you configured in your pom.xml (like I showed you above) you have to use the plugin name “tomcat7“. So you would build and deploy you app for example with the following Maven command:

mvn clean install tomcat7:run

This starts an embedded Tomcat using the plugin you have configured and uses the context path you have set.

The problem comes when you accidentally leave out the “7” at the end of the plugin name. If you deploy you app using:

mvn clean install tomcat:run

Maven will see that there are no plugins configured that has the name “tomcat“, but the build won’t fail because Maven has some conventions for finding plugins that you have not declared in your POM. In this case maven will find the org.codehaus.mojo:tomcat-maven-plugin and use it with default configuration. The default configuration means that the context path will be equal to the artifactId.

If you would like to read more about how Maven finds plugins that you have not configured, read the accepted answer in this Stackoverflow question.

So to sum it up, if you misspell the plugin name and use “tomcat” instead of “tomcat7“, Maven will not use the plugin that you configured, but another one with a default configuration. This could be the reason why your context path setting is not taken into account.

Of course, there can be other reasons for this kind of issue, but I have ran into this a couple of times and this was the solution for me.