<munit.version>1.2.0</munit.version>
<mule.munit.support.version>3.7.1</mule.munit.support.version>
MUnit Maven Support
MUnit provides a Maven plugin that allows you to run your MUnit tests as part of your continuous integration environment.
For information on redirecting logs to a file, see Logging in MUnit. |
Setting Up Your pom.xml File
MUnit is a composition of several modules, all of which are necessary to run your MUnit test. Maven offers as much flexibility as possible.
For MUnit to run properly with Maven, you need to add a few sections to your pom.xml
file.
If you are using Anypoint Studio, Maven integration is already solved for you. See Using Maven in Anypoint Studio for details. |
This documentation assumes you have the |
Do not combine MUnit modules of different versions. That is, the munit.version
should be the same across all MUnit artifacts in your pom.xml
, like the plugin or the runner.
Regarding the Mule MUnit support module, the mule.munit.support.version
should match the mule.version
. For example, 3.7.0
version of the support module would be compatible with 3.7.0
, 3.7.1
, 3.7.2
and other versions of Mule, but not necessarily with 3.6.0
.
MUnit Maven Plugin
The MUnit Maven Plugin allows you to run MUnit tests from Maven. To enable the plugin, add the following section to your pom.xml
.
<build>
<plugins>
...
<plugin>
<groupId>com.mulesoft.munit.tools</groupId>
<artifactId>munit-maven-plugin</artifactId>
<version>${munit.version}</version>
<executions>
<execution>
<id>test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
MUnit Folder
All the MUnit Test Suite files reside in src/test/munit
. You need to tell Maven to add this folder to the classpath.
<build>
...
<testResources>
<testResource>
<directory>src/test/munit</directory> (1)
</testResource>
<testResource>
<directory>src/test/resources</directory> (2)
</testResource>
</testResources>
...
</build>
1 | The actual MUnit test folder. |
2 | The normal resources folder, usually used to store other files. |
MUnit Dependencies
Listed below are the minimal artifacts required to enable MUnit to run from Maven.
<dependencies>
...
<dependency>
<groupId>com.mulesoft.munit</groupId>
<artifactId>mule-munit-support</artifactId>
<version>${mule.munit.support.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.mulesoft.munit</groupId>
<artifactId>munit-runner</artifactId>
<version>${munit.version}</version>
<scope>test</scope>
</dependency>
...
</dependencies>
MUnit Repositories
MUnit artifacts are deployed in the Mule Maven repositories, which you’ve probably seen before.
<repositories>
<repository>
<id>mulesoft-releases</id>
<name>MuleSoft Releases Repository</name>
<url>http://repository.mulesoft.org/releases/</url>
<layout>default</layout>
</repository>
</repositories>
You also need to add the Plugin repository.
<pluginRepositories>
<pluginRepository>
<id>mulesoft-release</id>
<name>mulesoft release repository</name>
<layout>default</layout>
<url>http://repository.mulesoft.org/releases/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
If you code your MUnit tests in Java, you don’t need the MUnit Maven Plugin nor the plugin repository. |
The MUnit Maven Plugin
The MUnit Maven Plugin makes it possible to run the XML-based tests. It has a few features we discuss below.
Running MUnit Tests From Maven
mvn clean test
Running a Specific MUnit Test Suite
You can instruct MUnit Maven Plugin to run only tests that belong to a specific test suite.
To do this, we use the property munit.test
.
mvn clean test -Dmunit.test=<regex-test-suite>
The property munit.test
accepts regular expressions. The expression is applied to the name of the MUnit Test Suite file. The regular expression language is the Java implementation.
The following is a valid example:
mvn clean test -Dmunit.test=.*my-test.*
You can leverage this feature by adding naming conventions to your MUnit Test suites.
Running Specific MUnit Tests
In the same way that you instruct MUnit to run one test suite, you can also tell it to run a specific test inside that test suite. To do so, we again make use of the property munit.test
, with one addition:
mvn clean test -Dmunit.test=<regex-test-suite>#<regex-test-name>
The addition is the special character #
. To the right of it you should type the test name. It also accepts regular expressions. The expression is applied to the attribute name
of the MUnit Test.
Regular expressions must be enclosed between double quotes.
The following is a valid example:
mvn clean test -Dmunit.test=".*my-test.*#.*test-scenario-1.*"
The tests inside the MUnit Test Suite that don’t match the regular expression is flagged as ignored. |
Skip MUnit Tests
Skipping All Tests
When building your application, you may want to prevent a test from running. MUnit leverages the same mechanism as Maven, so if you wish to skip tests, you can make use of the parameter skipTests
.
mvn clean package -DskipTests
Skipping Only MUnit Tests
MUnit also comes with another property that only prevents MUnit tests from running. While at the same time allowing any other test, like JUnit tests, to keep running.
If you wish to skip only MUnit tests, you can make use of the parameter skipMunitTests
.
mvn clean package -DskipMunitTests
The property skipMunitTests applies only to the XML based MUnit tests.
|
General Configurations
The MUnit Maven Plugin offers a minor set of configurations.
Setting System Variables
You may wish to define specific system variables needed for your MUnit test to run successfully. The example below shows how you can send them.
<plugin>
<groupId>com.mulesoft.munit.tools</groupId>
<artifactId>munit-maven-plugin</artifactId>
<version>${munit.version}</version>
<executions>
<execution>
<id>test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<systemPropertyVariables> (1)
<my.property.key>my.property.value></my.property.key>
</systemPropertyVariables>
</configuration>
</plugin>
1 | Sends variables. |
System Property variables override any property set in the mule-
app.properties
file or with a property placeholder.
You can override these variables using the For example:
|
Dynamic Ports
When testing a Mule application in a continuous integration (CI) environment, the following scenario is not uncommon:
Your application tries to open a specific port. The port is already in use. The application fails with a port binding exception.
This is bound to happen and the easy solution to this problem is to have your application use a free port. The MUnit Maven Plugin comes with a built in feature to do just that.
MUnit Dynamic Ports
instructs the MUnit Maven Plugin to look for unbound ports and reserve them before running the tests over the Mule application. Each port selected is placed in a system property under the name indicated in the configuration.
Afterwards the port number can be acquired by the application by the use of placeholders.
The Ports to be selected by the plugin are taken from the following range: [40000,50000)
|
Dynamic Ports feature is only available as part of the MUnit Maven Plugin, thus you can not expect this feature to work when running tests from inside Anypoint Studio. |
Enabling Dynamic Ports
In order to enable the feature, you need to add the following code to the configuration
section of the MUnit Maven Plugin:
<dynamicPorts>
<dynamicPort>a.dynamic.port</dynamicPort>
</dynamicPorts>
If you have the ${http.port}
placeholder in your application, the configuration looks something like:
<dynamicPorts>
<dynamicPort>http.port</dynamicPort>
</dynamicPorts>
Preparing Your Application
The part of the application trying to make use of a port must be parametrized by use of a placeholder. For instance, you may want to have your Mule application listening for HTTP traffic. In order to do that you should provide the following configuration:
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081"/>
<flow name="httpFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/"/>
</flow>
Now this application always listens in port 8081
. To make it dynamic, change it to:
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="${http.port}"/> (1)
<flow name="httpFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/" />
</flow>
1 | Notice the placeholder ${http.port} . |
With the application coded in this way, and the configuration of Dynamic Ports in place your application starts each run listening on a different port.
Coverage
MUnit used to have a basic coverage feature only available from Anypoint Studio.
Since MUnit version 1.2.0
this feature is also available from the command line by the use of the MUnit Maven Plugin.
Configuration
The following section covers how to configure MUnit Coverage.
A basic set of Coverage related features is in Anypoint Studio. However, the full set of features is only
available when running from Maven. Thus all of the configuration is done through the pom.xml
file.
Enabling Coverage
To enable MUnit Coverage, add the following configuration to the MUnit Plugin:
<plugin>
<groupId>com.mulesoft.munit.tools</groupId>
<artifactId>munit-maven-plugin</artifactId>
<version>${project.version}</version>
...
<configuration>
<coverage>
<runCoverage>true</runCoverage> (1)
</coverage>
</configuration>
</plugin>
1 | This enables the coverage feature |
When enabling MUnit Coverage, you only see a summary report in the console. By default no other action is taken so it’s merely informative.
This is how a summary report looks like:
[INFO] [CoverageManager] Printing Coverage Report...
[INFO] ===============================================================================
[INFO] MUnit Coverage Summary
[INFO] ===============================================================================
[INFO] * Resources: 3 - Flows: 6 - Message Processors: 7
[INFO] * Application Coverage: 71.43%
To configure the JSON report generation for the MUnit Plugin, you need to add the following configuration in your pom.xml
file:
<coverage>
<runCoverage>true</runCoverage>
<formats>
<format>json</format>
</formats>
</coverage>
Failing Build
One of the features of MUnit Coverage is to fail the build if a certain coverage level is not reached.
To make the build fail, add the following lines to the configuration:
<coverage>
<runCoverage>true</runCoverage>
<failBuild>true</failBuild> (1)
</coverage>
1 | Enable Fail Build Feature |
Now, the next logical step is to define the coverage levels.
MUnit Coverage handles three different levels:
-
Application
-
Resource
-
Flow
Here is how to define the required coverage level:
<coverage>
<runCoverage>true</runCoverage>
<failBuild>true</failBuild>
<requiredApplicationCoverage>20</requiredApplicationCoverage>
<requiredResourceCoverage>10</requiredResourceCoverage>
<requiredFlowCoverage>5</requiredFlowCoverage>
</coverage>
Each value represents a percentage. |
If you define coverage levels, but set the property failBuild
to false, and if the levels are not reached, a warning displays in the MUnit Coverage summary.
Something like this:
INFO] [CoverageManager] Printing Coverage Report...
[INFO] ===============================================================================
[INFO] MUnit Coverage Summary
[INFO] ===============================================================================
[INFO] * Resources: 3 - Flows: 6 - Message Processors: 7
[INFO] * Application Coverage: 71.43%
[NOTE]
[WARNING] ----------------------------- WARNING --------------------------------------
[WARNING] * Application coverage is below defined limit. Required: 100.0% - Current: 71.43% (1)
1 | Warning detailing which coverage level wasn’t meet |
If no level is defined, -1 is assumed, which indicates that the build won’t fail due to lack of coverage. |
Ignoring Flows
Another feature we provide is the ability to ignore a flow. This means that a flow doesn’t count as coverage data, doesn’t affect the overall number of message processors, and doesn’t cause a build to fail if the flow is not tested or if the flow doesn’t reach coverage metrics.
To ignore a flow, add the following lines to the configuration:
<coverage>
<ignoreFlows>
<ignoreFlow>the-name-of-your-flow</ignoreFlow> (1)
</ignoreFlows>
</coverage>
1 | The name of the flow you want to ignore. |
This is a list, so you can ignore as many flows as you need.
Reports
As we’ve shown before by default, MUnit Coverage shows summary report in the console. But that’s not the only option. MUnit Coverage currently offers two types of reports:
-
Console
-
HTML
-
JSON
The Console report, is printed in the console. It works with the summary report and shows details of each resource, flow, sub-flow, and batch, and its coverage level.
The HTML report shows the same information, which you can view in any web browser. To access the HTML report, browse your application folder structure:
-
${application.path}/target/munit-reports/coverage
Locate the file summary.html, which is the starting point of the report and lets you navigate through all the data.
The JSON report shows the same information as the HTML report, in a JSON format.
To access the JSON report file, browse your application folder structure:
${application.path}/target/munit-reports/coverage-json/report.json
To enable the reports, add the following configuration:
<coverage>
<runCoverage>true</runCoverage>
<formats>
<format>console</format> (1)
<format>html</format> (2)
<format>json</format> (3)
</formats>
</coverage>
1 | Console report |
2 | HTML report |
3 | JSON report |
You can have none, one, or all the report types added to your configuration. |
Working With Parent POMs
You can declare the MUnit plugin in a parent POM file and every child project under this file can choose to reference this definition.
In order to make a proper use of the MUnit plugin in a parent-child POM relationship, you need to include the MUnit plugin declaration in the <pluginManagement>
section of your parent pom.xml
file:
<?xml version="1.0" encoding="UTF-8"?>
<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>org.pirate</groupId>
<artifactId>pirate-pom</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<munit.version>1.2.0-SNAPSHOT</munit.version>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.mulesoft.munit.tools</groupId>
<artifactId>munit-maven-plugin</artifactId>
<version>${munit.version}</version>
<executions>
<execution>
<id>test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<coverage>
<runCoverage>true</runCoverage>
<failBuild>false</failBuild>
<requiredApplicationCoverage>0</requiredApplicationCoverage>
<requiredResourceCoverage>0</requiredResourceCoverage>
<requiredFlowCoverage>0</requiredFlowCoverage>
<formats>
<format>console</format>
<format>html</format>
</formats>
</coverage>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
This pirate-pom project declares the MUnit Maven plugin in its plugin management section, which defines a global configuration that each child under this parent can choose to reference, override or even ignore.
Inherit Parent’s Plugin
If you choose to inherit the MUnit plugin in your child POM files, you need to reference it in a <plugin> section of each child POM file individually:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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/maven-v4_0_0.xsd">
<parent>
<groupId>org.pirate</groupId>
<artifactId>pirate-pom</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>ninja</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>mule</packaging>
<name>Mule ninja Application</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<mule.version>3.8.0</mule.version>
<mule.tools.version>1.1</mule.tools.version>
<munit.version>1.2.0</munit.version>
<mule.munit.support.version>3.8.0</mule.munit.support.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>com.mulesoft.munit.tools</groupId>
<artifactId>munit-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
This quick sample references pirate-pom file as its parent and then declares the MUnit plugin in a <plugin>
section without specifying its <version>
because MUnit plugin configuration is being inherited from the <pluginManagement>
section in the parent.
Inherit Plugin and Override Parent’s Configuration
When inheriting the plugin from a parent POM file, you can also choose to override the parent’s configuration, but keep in mind that overriding completely suppresses the original configuration, requiring you to declare all necessary configurations again:
<plugin>
<groupId>com.mulesoft.munit.tools</groupId>
<artifactId>munit-maven-plugin</artifactId>
<configuration>
<coverage>
<runCoverage>true</runCoverage>
<formats>
<format>html</format>
</formats>
</coverage>
</configuration>
</plugin>
In this example, this child project is overriding the console coverage report, replacing it only by the HTML one, but since the values from the other elements in the parent (<failBuild>
, <requiredApplicationCoverage>
, <requiredResourceCoverage>
, <requiredFlowCoverage>
) are not being referenced, this child file won’t inherit them and the default values will apply.
Ignore Parent’s Plugin
Each child project under a parent pom
file can choose to ignore the plugin referenced in the parent’s plugin management section and not implement the plugin declared there.
By not declaring the Munit Plugin in your <plugin>
section, you avoid inheriting the plugin declared in pirate-pom:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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/maven-v4_0_0.xsd">
<parent>
<groupId>org.pirate</groupId>
<artifactId>pirate-pom</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>ninja</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>mule</packaging>
<name>Mule ninja Application</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<mule.version>3.8.0</mule.version>
<mule.tools.version>1.1</mule.tools.version>
<munit.version>1.2.0</munit.version>
<mule.munit.support.version>3.8.0</mule.munit.support.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.mule.tools.maven</groupId>
<artifactId>mule-app-maven-plugin</artifactId>
<version>${mule.tools.version}</version>
<extensions>true</extensions>
<configuration>
<copyToAppsDirectory>true</copyToAppsDirectory>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>project</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
</project>
Reading MUnit Test Results
This section briefly explains how to read the MUnit console logs.
=======================================================
=========== Running test-config.xml test ===========
=======================================================
Running testingEchoFlow
SUCCESS - Test testingEchoFlow finished Successfully.
===========================================================================
Number of tests run: 1 - Failed: 0 - Errors: 0 - Skipped: 0
===========================================================================
=====================================
Munit Summary
=====================================
>> test-config.xml test result: Errors: 0, Failures:0
=======================================================
=========== Running test-config.xml test ===========
=======================================================
Running testingEchoFlow
FAILURE - The test testingEchoFlow finished with a Failure.
expected:< Bye world!> but was:< Hello world!>
java.lang.AssertionError: expected:< Bye world!> but was:< Hello world!>
at testingEchoFlow.munit:assert-payload-equals{payloadIs-ref= Bye world!}(test-config.xml:22)
at testingEchoFlow.munit:assert-not-null{}(test-config.xml:21)
at echoFlow .mule:echo-component{}(mule-config.xml:8)
at testingEchoFlow.munit:set{payload-ref= Hello world!}(test-config.xml:19)
===========================================================================
Number of tests run: 1 - Failed: 1 - Errors: 0 - Skipped: 0
===========================================================================
=====================================
Munit Summary
=====================================
>> test-config.xml test result: Errors: 0, Failures:1
---testingEchoFlow <<< FAILED
=======================================================
=========== Running test-config.xml test ===========
=======================================================
Running testingEchoFlow
ERROR - The test testingEchoFlow finished with an Error.
Failed to invoke set. Message payload is of type: NullPayload
org.mule.api.MessagingException: Failed to invoke set. Message payload is of type: NullPayload
at testingEchoFlow.munit:set{payload-ref=#[string: Hello world!]}(test-config.xml:19)
Caused by: org.mule.api.expression.InvalidExpressionException: [Error: unknown class or illegal statement: org.mvel2.ParserContext@b6ba69]
[Near : {... string: Hello world! ....}]
^
[Line: 1, Column: 19]
at org.mule.el.mvel.MVELExpressionLanguage.validate(MVELExpressionLanguage.java:244)
at org.mule.el.mvel.MVELExpressionLanguage.evaluateInternal(MVELExpressionLanguage.java:195)
at org.mule.el.mvel.MVELExpressionLanguage.evaluate(MVELExpressionLanguage.java:169)
===========================================================================
Number of tests run: 1 - Failed: 0 - Errors: 1 - Skipped: 0
===========================================================================
=====================================
Munit Summary
=====================================
>> test-config.xml test result: Errors: 1, Failures:0
---testingEchoFlow <<< ERROR