Wednesday, April 9, 2014

Automated Arquillian Test with Managed Tomcat

I recent faces this issue. In my test code, I use JMockit for Mock and Arquillian to drive the server. In the beginning I used embedded tomcat for test. But there is one problem, Arquillian runs both Server(embedded Tomcat) and client code in the same JVM. If one class is mocked, it is mocked in both client and server. But I only want to mock at client side. I need to use Managed Tomcat for test. But  I do not want the hassle to manage the server. Moreover,  when code is downloaded by others, or tested in CI server, I want to the test to be run in an automatic fashion. To work towards this end, I automate the Tomcat download and configuration process.

First, use the maven-cargo plugin to download Tomcat automatically
    <!-- launch tomcat, deploy application before integration test -->
            <plugin>
                <groupId>org.codehaus.cargo</groupId>
                <artifactId>cargo-maven2-plugin</artifactId>
                <version>1.4.6</version>
                <executions>
                    <!-- install tomcat
                    So it could be used by arquillion managed
                     -->
                    <execution>
                        <id>install-container</id>
                        <phase>generate-test-resources</phase>
                        <goals>
                            <goal>install</goal>
                        </goals>
                    </execution>
                     <configuration>                  

  <!-- Container configuration -->
                    <container>
                        <containerId>tomcat7x</containerId>
                        <zipUrlInstaller>
                            <url>http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.52/bin/apache-tomcat-7.0.52.zip</url>
                            <downloadDir>${project.build.directory}</downloadDir>
                              <extractDir>${project.build.directory}</extractDir>
                        </zipUrlInstaller>
                    </container>
            </plugin>


Then configure the download tomcat so that it can be managed remotely by Arquillian
<!--  copy customized tomcat configuration -->
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <executions>
                  <execution>
                    <id>copy-tomcat-config</id>
                    <!-- here the phase you need -->
                    <phase>process-test-resources</phase>
                    <goals>
                      <goal>copy-resources</goal>
                    </goals>
                    <configuration>
                      <outputDirectory>${basedir}/target/apache-tomcat-7.0.52/apache-tomcat-7.0.52/conf</outputDirectory>
                      <resources>         
                        <resource>
                          <directory>${basedir}/src/test/resources/tomcat7x/conf</directory>
                        </resource>
                      </resources>             
                    </configuration>           
                  </execution>
                </executions>
              </plugin>

Here you prepare the configuration under /src/test/resources/tomcat7x/conf. They will be copied to installed Tomcat by this plugin.

Prepare the arquillian configuration so it knows how to communicate with managed tomcat: src/test/resources/arquillian.xml
<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">
      <!--
    https://docs.jboss.org/author/display/ARQ/Tomcat+7.0+-+Managed
     -->
    <container qualifier="tomcat-managed" default="true">
        <configuration>
            <property name="startupTimeoutInSeconds">20</property>
            <!-- The port to connect -->
            <property name="bindHttpPort">8888</property>
            <!--  the port to connect -->
<!--             <property name="jmxPort">8089</property> -->
            <property name="catalinaHome">target/apache-tomcat-7.0.52/apache-tomcat-7.0.52</property>
            <property name="outputToConsole">true</property>
             <property name="user">tomcat</property>
            <property name="pass">manager</property>
             <property name="host">localhost</property>
        </configuration>
    </container>
</arquillian>

The name of this configuration is tomcat-managed here.
Finally Let maven-surefire to use this arquillian configuration
    <!-- Fire unit test -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>                        <arquillian.launch>tomcat-managed</arquillian.launch>
                        <arquillian>tomcat-managed</arquillian>
                    </systemProperties>
                </configuration>
            </plugin>

Do not forget let arqillian to launch your managed tomcat for you.
<profile>
            <id>tomcat-managed</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <dependencies>
              <dependency>
                <groupId>org.jboss.arquillian.container</groupId>
                  <artifactId>arquillian-tomcat-managed-7</artifactId>
                  <version>1.0.0.CR6</version>
                  <scope>test</scope>
              </dependency>
            </dependencies>
        </profile>    



a PickList component for angularjs

First, what is a PickList? See a demo here: http://www.primefaces.org/showcase/ui/picklist.jsf.

The example above is a PickList in JSF. In one of my project, I need such component working in angularjs fashion. I did not find one by googling around. I decided to code one by myself.  This is first version: https://github.com/jasonzhang2022/picklist.

Here is an exmaple how to use it.
<select name="pktest" size="20"  
data-ng-options="v.name for v in toptions"  
data-picklist="" multiple data-ng-model="tselected">  
</select>
data-ng-options and data-ng-model are directives from angularjs itself. data-picklist is from this component. Once <select> is decorated with all the three attributes, you have an PickList.

Angularjs V.S JSF implementation.

Use Component
For component user, angularjs approach is super easy, just one extra attribute for select element. PickList in PrimeFace is not so easy. First, you need to understand the data model behind the component. Second you need to add some classes and codes in server to work together with the PickList.

UI customization:
Again, angular js wins. All the html is a regular html template decorated with regular angularjs directives. You can replace with your own html template easily.  I usually customize JSF component from JSF libraries. It is just really tough.

Component creation:
Super easy in angular js. All I created is 300-line file including html template. Again, It is hard in JSF. You need to create html template, javascript, renderer, etc and configure them in one component.

Test:
I do not know how you test the JSF component. I guess you can use some end-to-end test code such as selenium. This angular component itself has test code. All javascript logic is tested thoroughly.