Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Arquillian Unit Tests

DZone's Guide to

Arquillian Unit Tests

·
Free Resource

Many JEE and Spring projects in my company desperately need solid test cases. But the opposition to a test suite arises due to multiple reasons. The most interesting of those is the general apathy shown toward unit tests by our developers who do not want to code tests because they don't add value to their resume. Managers also discourage the team from wasting time on a good regression test suite. The value of a test suite is lost on everybody. 

I hope JBoss Arquillian can change these perspectives. Easy and clean container tests executed in the IDE help us test JEE/Spring aspects. The test suite can also enable the developers learn the intricacies of Spring and JEE if they study the code and design of Arquillian.


When I started using Arquillian I found that the JBoss Arquillian forum receives less questions and even lesser answers. That didn't help but the Arquillian showcase  has many examples. 


The Arquillian WildFly Test suite has more examples but is harder to understand.

I show a few basic testing rules which I learnt in this article.


Container


I installed WildFly and set the JBOSS_HOME variable to point to the installation and activate the Maven profile arq-jbossas-managed specified in the pom.xml. That is all. The Maven POM takes care of the container dependencies needed by Arquillian.  Many container adapters are supported.


Deployment

Learning to code using the ShrinkWrap API to create a Web deployment archive is the most important part. I have seen teams  deploy code hundreds of times a day to test simple features. Sometimes they need to connect to a client's virtual environment to deploy and test.


Arquillian deploys everything for us into a container automatically and repeatedly.


@Deployment

    public static WebArchive createWebArchive() {

        final WebArchive war=ShrinkWrap.create(WebArchive.class,"ShrinkWrap.war");

        JavaArchive jar = ShrinkWrap.create(JavaArchive.class)

                                //.addPackage("com.arquillian.jms.e2e");

                                  .addClass("com.arquillian.jms.e2e.MessageSender")

                                     .addClass("com.arquillian.jms.e2e.MessageSenderImpl")

                                     .addClass("com.arquillian.jms.e2e.ShrinkWrappedMessageTest");

        war.addAsLibrary(jar);

        war.addAsResource("applicationContext-another.xml");

        war.addAsResource("applicationContext.xml");

        war.addAsResource("spring-beans-embedded.xml");

        war.addAsResource("arquillian.xml");

        war.addAsResource("log4j.xml");

        loadDependencies( war );

        l.info(war.toString(Formatters.VERBOSE));

        return war;

    }


Adding Test and other classes


It is possible to add a package of classes or individual classes to the deployed WAR


Loading dependencies


There are many ways to load project dependencies.


Explicitly loading individual dependencies using the API


This code resolves the project dependencies that we need based on their artifactid, groupid and version

    private static void loadDependencies( final WebArchive war ){



        File xbean = Maven.

                resolver().

                    resolve("org.apache.xbean:xbean-spring:4.3")

                        .withoutTransitivity().asSingle(File.class);



        war.addAsLibraries(xbean);



        war.addAsLibraries(xbean);

        File springjms = Maven.

                resolver().

                    resolve("org.springframework:spring-jms:4.1.1.RELEASE")

                        .withoutTransitivity().asSingle(File.class);



        war.addAsLibraries(springjms);



        File springexpression = Maven.

                resolver().

                    resolve("org.springframework:spring-expression:4.2.0.RELEASE")

                        .withoutTransitivity().asSingle(File.class);



        war.addAsLibraries(springexpression);



        File springweb = Maven.

                resolver().

                    resolve("org.springframework:spring-web:4.2.0.RELEASE")

                        .withoutTransitivity().asSingle(File.class);



        war.addAsLibraries(springweb);



        File springcore = Maven.

                resolver().

                    resolve("org.springframework:spring-core:4.1.1.RELEASE")

                        .withoutTransitivity().asSingle(File.class);



        war.addAsLibraries(springcore);



        File springcontext = Maven.

                resolver().

                    resolve("org.springframework:spring-context:4.1.1.RELEASE")

                        .withoutTransitivity().asSingle(File.class);



        war.addAsLibraries(springcontext);



        File extensionspring = Maven.

                resolver().

                    resolve("org.jboss.arquillian.extension:arquillian-service-deployer-spring-3:1.0.0.Beta3")

                        .withoutTransitivity().asSingle(File.class);



        war.addAsLibraries(extensionspring);





        File springbeans = Maven.

                resolver().

                    resolve("org.springframework:spring-beans:4.1.1.RELEASE")

                        .withoutTransitivity().asSingle(File.class);



        war.addAsLibraries(springbeans);



        File activemqall = Maven.

                resolver().

                    resolve("org.apache.activemq:activemq-all:5.11.1")

                    .withoutTransitivity().asSingle(File.class);



        war.addAsLibraries(activemqall);



        File springaop = Maven.

                resolver().

                    resolve("org.springframework:spring-aop:4.2.0.RELEASE")

                    .withoutTransitivity().asSingle(File.class);



        war.addAsLibraries(springaop);



        File springtx = Maven.

                resolver().

                    resolve("org.springframework:spring-tx:4.1.1.RELEASE")

                    .withoutTransitivity().asSingle(File.class);



        war.addAsLibraries(springtx);



    }



Check the contents


Most of the problems I faced were caused by my lack of knowledge of how ShrinkWrap packages the artifacts. Following a streamlined process of debugging would have shortened the learning cycle.


This is one way to dump the contents of a packaged WAR

 l.info(war.toString(Formatters.VERBOSE));


            

Sep 05, 2015 11:19:50 PM com.arquillian.jms.e2e.ShrinkWrappedMessageTest createWebArchive

            INFO: ShrinkWrap.war:

            /WEB-INF/

            /WEB-INF/lib/

            /WEB-INF/lib/spring-jms-4.1.1.RELEASE.jar

            /WEB-INF/lib/arquillian-service-deployer-spring-3-1.0.0.Beta3.jar

            /WEB-INF/lib/spring-core-4.1.1.RELEASE.jar

            /WEB-INF/lib/0165719c-f843-4f44-94e1-58a6cb544351.jar

            /WEB-INF/lib/spring-beans-4.1.1.RELEASE.jar

            /WEB-INF/lib/spring-expression-4.2.0.RELEASE.jar

            /WEB-INF/lib/activemq-all-5.11.1.jar

            /WEB-INF/lib/spring-web-4.2.0.RELEASE.jar

            /WEB-INF/lib/xbean-spring-4.3.jar

            /WEB-INF/lib/spring-tx-4.1.1.RELEASE.jar

            /WEB-INF/lib/spring-context-4.1.1.RELEASE.jar

            /WEB-INF/lib/spring-aop-4.2.0.RELEASE.jar

            /WEB-INF/classes/

            /WEB-INF/classes/applicationContext-another.xml

            /WEB-INF/classes/arquillian.xml

            /WEB-INF/classes/spring-beans-embedded.xml

            /WEB-INF/classes/applicationContext.xml

            /WEB-INF/classes/log4j.xml





I was curious about the location of my test classes because they were not visible in this list and I thought it should be in /WEB-INF/lib/0165719c-f843-4f44-94e1-58a6cb544351.jar.  Arquillian allows us to dump the entire WAR to a location specified in arquillian.xml in order to inspect it further. In fact in this example that is the only purpose of arquillian.xml though it can be used for other purposes also.

arquillian.xml


    <?xml version="1.0" encoding="UTF-8"?>

    <arquillian xmlns="http://jboss.org/schema/arquillian"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://jboss.org/schema/arquillian

        http://jboss.org/schema/arquillian/arquillian_1_0.xsd">



    <engine>

        <property name="deploymentExportPath">D:\arquillian</property>

    </engine>

    </arquillian>


The exported WAR in my case was _DEFAULT___DEFAULT__ShrinkWrap.war and I verified that WEB-INF/lib/0165719c-f843-4f44-94e1-58a6cb544351.jar contains the classes added by me.

It is also possible to print the contents using the API like this.


    private static void dumpContents(  final WebArchive war  ){



         String file = null;

            for( Entry<ArchivePath, Node> content : war.getContent().entrySet()){

               file = content.getValue().toString();

                   l.info("WAR [" + content.getValue().toString() + "]");

           }

    }


Importing an existing WAR using ShrinkWrap


Usually we already have a Web or Enterprise archive that we want to execute tests on. The following code uses an existing WAR.

 

   @Deployment

    public static WebArchive createExistingWebArchive() {

        WebArchive war = ShrinkWrap.create( ZipImporter.class,

                                           "ShrinkWrap.war")

                                   .importFrom(new File("D:/arquillian/ExistingShrinkWrap.war"))

                 .as(WebArchive.class) ;

        return war;

    }



applicationContext.xml


This is like any other such file.

           <?xml version="1.0" encoding="UTF-8"?>

        <beans xmlns="http://www.springframework.org/schema/beans"

            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

            xmlns:jms="http://www.springframework.org/schema/jms"

            xmlns:oxm="http://www.springframework.org/schema/oxm" 

            xmlns:p="http://www.springframework.org/schema/p"

            xmlns:context="http://www.springframework.org/schema/context"

            xsi:schemaLocation="http://www.springframework.org/schema/beans   

            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  

            http://www.springframework.org/schema/jms  

            http://www.springframework.org/schema/jms/spring-jms-3.0.xsd

            http://www.springframework.org/schema/context 

            http://www.springframework.org/schema/context/spring-context-3.0.xsd 

            http://www.springframework.org/schema/oxm 

            http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd"

            default-lazy-init="true">







           <import resource="spring-beans-embedded.xml"/>

           <import resource="applicationContext-another.xml"/>



           <context:component-scan base-package="com.arquillian.jms.e2e" />

           <context:annotation-config />   

        </beans>


JMS setup 


I used a sample setup that creates an embedded Broker.


    <beans 

          xmlns="http://www.springframework.org/schema/beans" 

          xmlns:amq="http://activemq.apache.org/schema/core"

          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

          http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">



      <!--  lets create an embedded ActiveMQ Broker -->

      <amq:broker useJmx="false" persistent="false">

        <amq:transportConnectors>

          <amq:transportConnector uri="tcp://localhost:0" />

        </amq:transportConnectors>

      </amq:broker>



       <!--  ActiveMQ destinations to use  -->

      <amq:queue id="destination"  physicalName="org.apache.activemq.spring.Test.spring.embedded"/>



      <!-- JMS ConnectionFactory to use, configuring the embedded broker using XML -->

      <amq:connectionFactory id="jmsFactory" brokerURL="vm://localhost"/>



      <!--  Default Destination Queue Definition-->

        <bean id="defaultDestination" class="org.apache.activemq.command.ActiveMQQueue">

            <constructor-arg index="0" value="test"/>

        </bean>



      <bean id="consumerJmsTemplate" class="org.springframework.jms.core.JmsTemplate">

        <property name="connectionFactory" ref="jmsFactory"/>

       <property name="defaultDestination" ref="defaultDestination" />

      </bean>





    </beans>


Debug logs for ActiveMQ Broker


The logs used to verify that the broker starts and stops properly.


    

INFO : org.apache.activemq.broker.BrokerService - Using Persistence Adapter: MemoryPersistenceAdapter

    INFO : org.apache.activemq.broker.BrokerService - Apache ActiveMQ 5.11.1 (localhost, ID:LT032871-59520-1441371762665-0:1) is starting

    INFO : org.apache.activemq.transport.TransportServerThreadSupport - Listening for connections at: tcp://127.0.0.1:59521

    INFO : org.apache.activemq.broker.TransportConnector - Connector tcp://localhost:0 started

    INFO : org.apache.activemq.broker.BrokerService - Apache ActiveMQ 5.11.1 (localhost, ID:LT032871-59520-1441371762665-0:1) started

    INFO : org.apache.activemq.broker.BrokerService - For help or more information please see: http://activemq.apache.org

    WARN : org.apache.activemq.broker.BrokerService - Memory Usage for the Broker (1024 mb) is more than the maximum available for the JVM: 494 mb - resetting to 70% of maximum available: 346 mb

    INFO : org.hibernate.validator.internal.util.Version - HV000001: Hibernate Validator 5.1.3.Final

    INFO : org.apache.activemq.broker.TransportConnector - Connector vm://localhost started

    INFO : org.apache.activemq.broker.TransportConnector - Connector vm://localhost stopped

    INFO : org.apache.activemq.broker.TransportConnector - Connector vm://localhost started

    INFO : org.apache.activemq.broker.TransportConnector - Connector vm://localhost stopped

    INFO : org.apache.activemq.broker.BrokerService - Apache ActiveMQ 5.11.1 (localhost, ID:LT032871-59520-1441371762665-0:1) is shutting down

    INFO : org.apache.activemq.broker.TransportConnector - Connector tcp://localhost:0 stopped

    INFO : org.apache.activemq.broker.BrokerService - Apache ActiveMQ 5.11.1 (localhost, ID:LT032871-59520-1441371762665-0:1) uptime 0.443 seconds

    INFO : org.apache.activemq.broker.BrokerService - Apache ActiveMQ 5.11.1 (localhost, ID:LT032871-59520-1441371762665-0:1) is shutdown




    

 pom.xml



    <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>scos.hrg</groupId>

    <artifactId>arquillian-e2e</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <dependencies>  



          <dependency>

             <groupId>org.springframework</groupId>

             <artifactId>spring-context</artifactId>

             <version>4.1.1.RELEASE</version>

          </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-tx</artifactId>

            <version>4.1.1.RELEASE</version>

        </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-aop</artifactId>

            <version>4.2.0.RELEASE</version>

        </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-web</artifactId>

            <version>4.2.0.RELEASE</version>

        </dependency>

         <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-expression</artifactId>

            <version>4.2.0.RELEASE</version>

        </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-beans</artifactId>

            <version>4.1.1.RELEASE</version>

        </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-core</artifactId>

            <version>4.1.1.RELEASE</version>

        </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-jms</artifactId>

            <version>4.1.1.RELEASE</version>

        </dependency>

      <dependency>

            <groupId>org.apache.activemq</groupId>

            <artifactId>activemq-all</artifactId>

            <version>5.11.1</version>

        </dependency>



        <dependency>

            <groupId>org.jboss.arquillian.extension</groupId>

            <artifactId>arquillian-service-deployer-spring-3</artifactId>

            <version>1.0.0.Beta3</version>

        </dependency>

        <dependency>

            <groupId>org.jboss.arquillian.extension</groupId>

            <artifactId>arquillian-service-integration-spring-inject</artifactId>

            <scope>test</scope>

        </dependency>



        <dependency>  

           <groupId>org.jboss.arquillian.junit</groupId>  

           <artifactId>arquillian-junit-container</artifactId>  

             <version>1.1.8.Final</version>  

           <scope>test</scope>  

        </dependency>  

        <dependency>

                <groupId>org.jboss.arquillian.core</groupId>

                <artifactId>arquillian-core-api</artifactId>

                <version>1.1.4.Final</version>

        </dependency>

        <dependency>

            <groupId>org.jboss.shrinkwrap.resolver</groupId>

            <artifactId>shrinkwrap-resolver-impl-maven</artifactId>

            <version>2.1.0</version>  

        </dependency>          

        <dependency>

            <groupId>org.jboss.arquillian.extension</groupId>

            <artifactId>arquillian-service-integration-spring-inject</artifactId>

            <version>1.0.0.Beta3</version>

        </dependency>

    </dependencies>



    <profiles>

        <profile>

            <id>arq-jbossas-managed</id>

            <dependencies>

                <dependency>

                    <groupId>org.wildfly</groupId>

                    <artifactId>wildfly-arquillian-container-managed</artifactId>

                    <version>8.2.0.Final</version>

                </dependency>

            </dependencies>

        </profile>

    </profiles>

</project>


A sample JMS Unit Test


This part is a sample test found in Arquillian showcase. The is executed by the IDE showing success as a green bar.

    package com.arquillian.jms.e2e;
    public interface MessageSender {
            void sendMessage(String message);
    }


    package com.arquillian.jms.e2e;



    import javax.jms.JMSException;

    import javax.jms.Message;

    import javax.jms.Session;



    import org.springframework.beans.factory.annotation.Autowired;

    import org.springframework.jms.core.JmsTemplate;

    import org.springframework.jms.core.MessageCreator;

    import org.springframework.stereotype.Component;



    @Component

    public class MessageSenderImpl implements MessageSender {



        @Autowired

        private JmsTemplate consumerJmsTemplate;



        public void sendMessage(final String message) {



            consumerJmsTemplate.send(new MessageCreator() {

                public Message createMessage(Session session) throws JMSException {



                    return session.createTextMessage(message);

                }

            });

        }

    }


    @Test

    public void checkJmsTemplate() throws Exception {

        assertNotNull(consumerJmsTemplate);

        messageSender.sendMessage("Test");

        Message result = consumerJmsTemplate.receive("test");

        l.info( ((TextMessage)result).getText());

    }   


The source is in Arquillian Source.

Topics:
arquillian ,unit test

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}