07 - Maven Automatization techniques

7. Automation techniques

            7.1 Project modularization

            7.2 Dependency management

                        7.2.1 Transitive dependencies

                        7.2.2 Dependency scope

            7.3 Quality assurance

            7.4 Test Driven Development         

            7.5 Acceptance testing automation

            7.6 Deployment automation

            7.7 Reports generating

            7.8 Documentation

 

The automation techniques used for the building of software projects offer the advantage of reducing the human errors that could appear during the process of building manually the software.

Builds are faster, efficiency is better and products improve in quality. Automation is absolute necessary today in software engineering.

 

7.1 Project modularization

A large enterprise application needs to interact with database, work with services, provide user web interface and share API for other applications to consume.

Maven multi-module projects are made to support such a large enterprise application.

Parent Project contains Child Projects or Modules. The parent project’s POM file contains references to all the sub-modules. Each sub-module can have different package value.

                

For example for a project with two modules:

 

                      

The POM will contain:

<project...>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.test</groupId>
    <artifactId>myapp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>myapp-application</module>
        <module>myapp-web</module>
    </modules>
</project>

The result after building a multi-module project will be displayed in the console :

Results:
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ myapp-web ---
[INFO] Building jar: C:\MyWorkspace\myapp\myapp-web\target\myapp-web-0.0.1-SNAPSHOT.jar
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ myapp-web ---
[INFO] Installing C:\MyWorkspace\myapp\myapp-web\target\myapp-web-0.0.1-SNAPSHOT.jar to C:\temp\com\test\myapp-web\0.0.1-SNAPSHOT\myapp-web-0.0.1-SNAPSHOT.jar
[INFO] Installing C:\MyWorkspace\myapp\myapp-web\pom.xml to C:\temp\com\test\myapp-web\0.0.1-SNAPSHOT\myapp-web-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO]myapp .............................................. SUCCESS [  2.512 s]
[INFO] myapp-application .................................. SUCCESS [ 42.394 s]
[INFO] myapp-web .......................................... SUCCESS [  2.263 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 47.699 s
[INFO] Finished at: 2014-10-18T19:42:41+03:00
[INFO] Final Memory: 10M/25M
[INFO] ------------------------------------------------------------------------

 

7.2 Dependency management

Dependency management is one of the most powerful features of maven. After declaring explicitly all the dependencies for a project in the POM file Maven reads all the information and decides which jars must be loaded from the repositories.

In parent POM it can be added the tag <dependencyManagement>. 

<dependencyManagement>
<dependencies>
            <dependency>                <groupId>org.springframework</groupId>                <artifactId>spring</artifactId>
                <version>${springframework.version}</version>
            </dependency>
            <dependency>                <groupId>org.springframework</groupId>
                <artifactId>spring-agent</artifactId>
                <version>${springframework.version}</version>
            </dependency>
    </dependencies>
</dependencyManagement>

In child’s <dependencies> tag the dependency version can be omitted:

<dependencyManagement>
<dependencies>
            <dependency>                <groupId>org.springframework</groupId>                <artifactId>spring</artifactId>
            </dependency>
            <dependency>                <groupId>org.springframework</groupId>
                <artifactId>spring-agent</artifactId>
            </dependency>
    </dependencies>
</dependencyManagement>

Maven selects a defined list of dependencies by dependency mediation mechanism. If two dependency versions are at the same depth in the dependency tree then the first declared dependency is used.

 

7.2.1 Transitive dependencies

Maven resolves transitively all the required jars for a build. Transitiveness means that:

         if  A->B and B->C then A->C

Transitive dependencies can generate conflicts in the dependency tree for example:

The conflict in the above diagram example comes from the different versions of the jars commons-logging one having the version 1.0.2 and other version 1.1.1. With dependency mediation mechanism Maven will select the version 1.1.1 of commons-logging jar. The explanation should be that the dependency with version 1.1.1 is the newest. But in reality the version value has is not importance for the dependency mediation mechanism.

Other example:

Maven will select the dependency located at the smallest distance from the root of the tree. The dependency commons-logging-1.1.1 has the distance 1 from the root and commons-logging-1.0. 2

It is possible that the version of a dependency could be specified explicitly like this:

        <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>[1.0.2]</version>
        </dependency>

Square brackets were added around the version this means that the version will be only 1.0.2 all the time during the build.

 

7.2.2 Dependency scope

Because dependencies can be resolved transitively are they are defined in POM, we don’t need all the dependencies in all the cases. The role of a dependency can be defined by <scope/> tag or by adding the tag <optional>true</optional>. Maven dependencies have six scopes:

Compile

Default scope. The dependencies are available in the classpath.

Provided

The JDK environment provides dependencies at runtime.For a web application it is not necessary to include in the WEB-INF/lib this dependency.

Runtime

Dependencies are required at runtime and are specified in the runtime classpaths. It is not needed to compile the main source, tests or running the final artifact.

Test

Dependencies are required for test compilation and execution.

System

Dependencies are always available.

Import

Dependecies included in POM by <dependencyManagement/>tag.

Example of dependency with provided scope:

            <dependency>
                <groupId>javax.el</groupId>
                <artifactId>el-ri</artifactId>
                <version>1.2</version>
                <type>jar</type>
                <scope>provided</scope>
            </dependency>

The behavior of each scope depending of goals depends on the type of the project. If the project is the main project whose POM is the parent then the child project depends directly on this project.

Example of dependency with compile scope:

            <dependency>
                <groupId>org.richfaces.framework</groupId>
                <artifactId>richfaces-api</artifactId>
                <version>3.3.1.GA</version>
                <type>jar</type>
                <scope>compile</scope>
            <dependency>

 

7.3 Quality assurance

Maven has many tools for software quality assurance (SQA). The SQA consist of a means of monitoring the software engineering processes and methods used to ensure quality. The used methods in QA are many and varied, and may include ensuring conformance to one or more standards. SQA covers the entire software development process.

 

7.4 Test Driven Development

Maven makes unit testing and integration testing being part of the build lifecycle. If the project is generated with maven-achetype-quickstart / achetype it would already contain the Junit dependency and some test classes.

Unit tests run always before package and require 100% success so that the build could go on.

Integration Tests require the project artifact and are run after package phase but before install. Like Unit Tests require 100% success before going on.

In order to run tests junit dependency must be included in POM:

<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>

        

7.5 Acceptance testing automation

Acceptance tests are called also regression tests or functional tests. They don’t run every time and could be part of a profile.

They run after install and before deploy. Regression tests (previous acceptance tests) -already done should be successful completely. 

Functional tests (acceptance tests) need to be successful at release time.

Performance/stress tests are other form of acceptance tests.

In order to execute acceptance test for a multi-module maven project the modules that should be tested separately can be referenced from a profile.

For example for a project with two modules:

                 

For example the pom.xml of the parent module will contain:

<project ....>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.test</groupId>
    <artifactId>myapp</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <packaging>pom</packaging>
    <modules>
        <module>myapp-application</module>
    </modules>
    <profiles>
        <profile>
            <id>profile-acceptance</id>
            <modules>
                <module>myapp-acceptance-test</module>
            </modules>
        </profile>
    </profiles>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.11</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

The pom.xml of the module myapp-acceptance-test will contain:

<project..>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.test</groupId>
<artifactId>myapp</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>myapp-acceptance-test</artifactId>
<packaging>jar</packaging>
<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>
</project>

We will add the class:

importorg.junit.Test;
import static junit.framework.TestCase.assertTrue;
public class AcceptanceTest {
 @Test
    public void testMethod() {
        assertTrue("The tests are executed.", true);
    }
}

The pom.xml of the module application will contain:

<project...>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.test</groupId>
<artifactId>myapp</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>myapp-application</artifactId>
<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>
</project>

And the testv class:

importorg.junit.Test;
import static junit.framework.TestCase.assertTrue;
/**
 * Unit test for simple App.
 */
public class AppTest {
    @Test
    public void testMethod() {
        assertTrue("The tests are executed.", true);
    }
}

From the window Run Configuration of Eclipse we can configure the Maven build:

                 

Or we can run from the folder of myapp with the command:

       mvn clean install –P acceptance

This command will perform clean and install for myapp-application module and for myapp-aceptance-test module.

Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ myapp-acceptance-test ---
[INFO] Building jar: C:\MyWorkspace\myapp\myapp-acceptance-test\target\myapp-acceptance-test-0.0.1-SNAPSHOT.jar
[INFO] 
[INFO] --- maven-install-plugin:2.4:install (default-install) @ myapp-acceptance-test ---
[INFO] Installing C:\MyWorkspace\myapp\myapp-acceptance-test\target\myapp-acceptance-test-0.0.1-SNAPSHOT.jar to C:\temp\com\test\myapp-acceptance-test\0.0.1-SNAPSHOT\myapp-acceptance-test-0.0.1-SNAPSHOT.jar
[INFO] Installing C:\MyWorkspace\myapp\myapp-acceptance-test\pom.xml to C:\temp\com\test\myapp-acceptance-test\0.0.1-SNAPSHOT\myapp-acceptance-test-0.0.1-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] myapp .............................................. SUCCESS [  2.544 s]
[INFO] myapp-application .................................. SUCCESS [ 32.641 s]
[INFO] myapp-acceptance-test .............................. SUCCESS [  2.619 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 38.558 s
[INFO] Finished at: 2014-10-18T19:14:28+03:00
[INFO] Final Memory: 10M/25M
[INFO] ------------------------------------------------------------------------

Acceptance test can verify problems that unit tests cannot do. The acceptance profile will be executed on the Continuous Integration (CI) server. This method helps also to separate slow tests by fasts tests.

7.6 Deployment automation

Automating Continuous Integration pipeline process can be very difficult with extra effort necessaryand configurations hard to do. The process is made easier with Maven.

The Maven Plugins designed for deployment process can add artifact(s) to a remote repository during the deploy phase.

The artifacts are not only copied to a repository but the metadata updating.

Deployment locations are handled in the distribution Management tag section from POM file. It is located after dependencies tag:

<distributionManagement>
<repository>
<id>serverId</id>
<name>Example Repository</name>
<url>..</url>
</repository>
</distributionManagement>

ServerId refers to the same server from settings.xml file. In settings.xml file the user and password are used for authentication information for the repositories URL can be based on protocols like FTP,SCP or SFTP and depending on this it will be necessary additional information (authentication or other permissions).

Deployment can be done to a cross platform (wagon transport with wagon ftp and wagon –ssh-external) or system-specific manner.

Apache Maven Deploy plugin is the tool used by Maven for automating deployment.

It uses two goals:

       deploy:deploy

deploy all the project’s artifacts

       deploy:deploy-file:

deploy a single artifact file

The deployment can be executed manually from the project folder location with the command:

       mvn deploy

 

7.7 Reports generating

Reports generated by Maven can be classified in more categories:

  • Code quality reports
  • Unit testing reports
  • Test coverage reports

Maven Surefire Report Plugin can be used to generate reports of the project’s unit tests. In POM the tag report has to be added.

<project>
…
<reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-report-plugin</artifactId>
            </plugin>
            <configuration>
                <reportFormat>brief</reportFormat>
                <useFile>false</useFile>
            </configuration>
        </plugins>
</reporting>
…
</project>

The Surefire plugin provides a goal

       surefire:test

The reports can be found in

       ${basedir}/target/surefire-reports.

Tests can be created for:

        TestNG

        JUnit( 3.8 or 4.x)

        Plain Java (POJO) tests

The command lines used by Surefire are:

         mvn test

If we want the output that be driven to a file not in console:

          mvn test –Dsurefire.useFile=true

In configuration tag there can be specified the exclusions ( java test clases ) or inclusions. For example:                                   

<configuration>
                <excludes>
                    <exclude>**/TestBean.java</exclude>
                </excludes>
            </configuration>
.            …

Code quality reports can be generated with some Maven plugins. The developers should follow common conventions and standards for code quality.

The checks made by Maven tools cover the following:

  • Annotations
  • Block checks
  • Class design
  • Duplicate code
  • Imports

 

7.8 Documentation

Documentation is very important for open source and enterprise distributed projects for increasing the productivity in the working team.

Maven can be used to automate the process of documentation. There are several Maven plugins used for generating the documentation for a project such as Docbkk Maven Plugin.

This plugin can be used for conversion of DocBook(semantic markup language used for technical documentation) into PDF,HTML, etc.

Other tool used to generate API documentation directly from the source code is Maven Javadoc plugin. This tool uses the Javadoc tool and generates API documentation from source code in HTML format.

The plugin can be added to the build tag in POM.

<project>
  ...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.7</version>
<configuration>            ...
</configuration>
</plugin>
</plugins>
    ...
</build>
...
</project>

Some examples goals to be executed with Javadoc:

mvnJavadoc:Javadoc
mvnJavadoc:jar
mvnJavadoc:aggregate
mvnJavadoc:aggregate-jar
mvnJavadoc:test-javadoc
mvnJavadoc:test-jar
mvnJavadoc:test-aggregate
mvnJavadoc:test-aggregate-jar

The aggregate goal in Javadoc plugin is used to aggregate all the javadocs of all the modules in a single Java report.

Maven project sites contain Javadocs and binary releases. They can be deployed to a remote server.

Maven site documentation generation can be made with the aid of Maven-site-plugin. 

Like us on Facebook