1. 程式人生 > >Arquillian測試框架快速上手教程 (一)

Arquillian測試框架快速上手教程 (一)

本系列教程共五篇,分別是:

二、JBoss Forge、ShrinkWrap快速指南

五、使用 Arquillian 在雲端進行測試

其中,Web容器以JBoss-as-7.1.1為例,工程以maven目錄結構為準。

本文所涉及到的內容有:

1. Arquillian

2. Maven

3. JUnit

4. Seam Framework

5. ShrinkWrap

6. JBoss Forge

Arquillian簡介

Arquillian是一個基於JUnit,由JBoss開發的新型測試框架,其主要目的是簡化Java專案整合測試和功能測試的編寫,讓它們能像單元測試一樣簡單。Arquillian能真正在Web容器中執行測試,它主要通過三種方式與容器進行互動: 1.  嵌入式(embedded)。Arquillian和Web容器在同一個JVM中執行。 2. 受管理的(managed)。由Arquillian決定何時啟動、關閉Web容器以便向容器中部署、執行測試。 3. 遠端的(remote)。開發者事先啟動Web容器,Arquillian連線該容器並將測試部署到容器中執行。

一個最簡單的單元測試

建立maven工程

這裡我們使用JBoss Forge來幫助我們快速建立maven標準目錄和基本的pom.xml檔案。 首先啟動Forge:
forge

新建專案 arquillian-demo,指定包名為cn.demo:
new-project --named arquillian-demo --topLevelPackage cn.demo

這裡就用這2條命令,我們將會手動編輯pom檔案來新增arquillian的相關依賴。關於Forge的詳細安裝、使用方法,參見我另一篇文章:Debian-7.1下JBoss Forge + Arquillian測試環境搭建 為了方便編輯,我們將該專案匯入至eclipse中: 在eclipse選單欄中選擇 File --> Import,在彈出的對話方塊中選擇 "Existing Maven Project"。這樣匯入的好處是Eclipse會自動分析pom.xml檔案,自動根據依賴設定classpath,寫錯了也能第一時間得到錯誤提示。

新增Arquillian相關依賴

開啟pom.xml,我們能看到Forge已經為我們自動生成了以下內容:
<modelVersion>4.0.0</modelVersion>
	<groupId>cn.demo</groupId>
	<artifactId>arquillian-demo</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<repositories>
		<repository>
			<id>JBOSS_NEXUS</id>
			<url>http://repository.jboss.org/nexus/content/groups/public</url>
		</repository>
	</repositories>
	<build>
		<finalName>arquillian-demo</finalName>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</build>

我們需要新增 dependency 和 dependencyManagement節點,修改完成後內容如下:
<modelVersion>4.0.0</modelVersion>
	<groupId>cn.demo</groupId>
	<artifactId>arquillian-demo</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<repositories>
		<repository>
			<id>JBOSS_NEXUS</id>
			<url>http://repository.jboss.org/nexus/content/groups/public</url>
		</repository>
	</repositories>
	<build>
		<finalName>arquillian-demo</finalName>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<!-- newly add starts -->
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.jboss.arquillian.junit</groupId>
			<artifactId>arquillian-junit-container</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.jboss.arquillian</groupId>
				<artifactId>arquillian-bom</artifactId>
				<version>1.1.3.Final</version>
				<scope>import</scope>
				<type>pom</type>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<!-- newly add ends -->

儲存後,eclipse會自動從遠端倉庫中下載相關jar包,稍等即可。

編寫Bean和測試類

我們首先編寫一個Hello類,內容如下:
package cn.demo;

public class Hello {
	public String sayHello(String name) {
		return "hello," + name;
	}
}

該類的功能非常簡單,傳入一個名字,然後輸出 hello + 名字。下面我們為這個類寫單元測試。 新建HelloTest類,程式碼如下:
package cn.demo;

import javax.inject.Inject;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
public class HelloTest {
	@Inject
	private Hello helloBean; // 注入一個Hello物件
	
	@Deployment
	public static JavaArchive createDeployment() {
		return ShrinkWrap.create(JavaArchive.class).addClass(Hello.class)
				.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
	}

	@Test
	public void isHelloValid() {
		Assert.assertNotNull(helloBean); // 判斷注入是否成功
		Assert.assertEquals("hello,Neo", helloBean.sayHello("Neo")); // 判斷返回值是否正確
	}
}

程式碼說明: 一個Arquillian測試必須有三部分內容,分別是: 1. @RunWith(Arquillian.class)註解。 2. 一個公有的、靜態的、標註了@Deployment註解並返回一個Test Archive(稍後說明)的方法。 3. 至少有一個方法標有@Test註解。 @RunWith(Arquillian.class)註解的功能是通知 JUnit 讓 Arquillian 接過控制權,做為測試的控制器(Test Controller)。那@Deployment是做什麼用的呢?前面說過,Arquillian可以將測試直接部署到JBoss中執行,那怎麼部署,部署哪些內容,就由這個標有@Deployment註解的方法來決定。Arquillian使用 ShrinkWrap API 來建立jar包、向jar包中新增資源(比如一個類),然後 ShrinWrap 會根據我們定義好的jar包生成一個真正的jar檔案,最後由Arquillian把這個jar包部署到JBoss中去。本例中,首先呼叫ShrinkWrap類的靜態方法 create(),傳遞 JavaArchive.class 以指定我們要建立的是jar型別的檔案,然後呼叫 addClass() 方法向jar檔案中新增類,呼叫 addAsManifectResource() 方法向jar中新增一個空的 beans.xml,最後將結果返回。關於ShrinkWarp的詳細使用方法,參見官方的快速指南

新增容器介面卡(Container Adapter)

Container Adapter是溝通 Arquillian 和 Web容器的橋樑,Arquillian 通過不同的 Container Adapter 來判斷到底在哪種Web容器上執行測試,並通過它來控制容器。只要一個Web容器有其對應的Container Adapter,那麼這個容器說可以執行 Arquillian測試。我們以remote方式的 JBoss-As-7.1.1(即開發者需事先啟動JBoss,Arquillian會自動連線這個JBoss以執行測試)為例: 首先向pom.xml中新增profiles節點,內容如下:
<profiles>
		<profile>
			<id>arq-jbossas-remote</id>
			<dependencies>
				<dependency>
					<groupId>org.jboss.spec</groupId>
					<artifactId>jboss-javaee-6.0</artifactId>
					<version>1.0.0.Final</version>
					<type>pom</type>
					<scope>provided</scope>
				</dependency>
				<dependency>
					<groupId>org.jboss.as</groupId>
					<artifactId>jboss-as-arquillian-container-remote</artifactId>
					<version>7.1.1.Final</version>
					<scope>test</scope>
				</dependency>
				<dependency>
					<groupId>org.jboss.arquillian.protocol</groupId>
					<artifactId>arquillian-protocol-servlet</artifactId>
					<scope>test</scope>
				</dependency>
			</dependencies>
		</profile>
	</profiles>

這裡用profile的一大好處是,我們可以靈活的切換不同的Web伺服器。比如,我們想在JBoss上跑測試,就執行
mvn test -Parq-jbossas-remote

如果我們想在GlassFish上執行測試,就可以定義一個名為 arq-glassfish-remote的profile,然後執行:
mvn test -Parq-glassfish-remote


執行測試

切換到工程根目錄下,執行
mvn clean install -Dmaven.test.skip=true
注: -Dmaven.test.skip=true 的意思是讓maven在執行clean install指令時不要進行測試。
mvn test -Parq-jbossas-remote

輸出結果如下,則測試成功。(別忘了要事先啟動JBoss!)

以managed方式執行測試

前面說過Arquillian可以以managed 的方式與JBoss進行互動,特點是我們不必事先啟動JBoss,而在執行測試時,Arquillian會自動啟動JBoss,並在完成測試後自動關閉JBoss。下面舉例說明如何操作。  首先,新建一個profile節點,內容如下:
<profile>
			<id>arquillian-jbossas-managed</id>
			<dependencies>
				<dependency>
					<groupId>org.jboss.spec</groupId>
					<artifactId>jboss-javaee-6.0</artifactId>
					<version>1.0.0.Final</version>
					<type>pom</type>
					<scope>provided</scope>
				</dependency>
				
				<dependency>
					<groupId>org.jboss.as</groupId>
					<artifactId>jboss-as-arquillian-container-managed</artifactId> <!-- 注意這裡換成了managed而不是remote -->
					<version>7.1.1.Final</version>
					<scope>test</scope>
				</dependency>
				<dependency>
					<groupId>org.jboss.arquillian.protocol</groupId>
					<artifactId>arquillian-protocol-servlet</artifactId>
					<scope>test</scope>
				</dependency>
			</dependencies>
		</profile>

然後,為了讓Arquillian “知道” 我們的JBoss放在哪, 我們需要在 main/src/resource 目錄下建立一個名為 arquillian.xml的檔案,通過這個檔案我們可以設定 arquillian 的很多屬性,類似於 web.xml 的功能。 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">
    <container qualifier="jbossas-managed" default="true">
        <configuration>
            <property name="jbossHome">你的JBoss安裝目錄</property>

        </configuration>
    </container>
</arquillian>


切換到專案根目錄下,執行
mvn test -Parquillian-jbossas-managed

從控制檯輸出可以看到,到 test 階段時,Arquillian 會啟動JBoss :
然後部署並執行測試,最後undeploy並關閉JBoss:

在我們的ftc的seam專案中如何使用Arquillian?

事實上,seam-2.3已經在pom檔案自動加入Arquillian的相關依賴了。我們可以直接在 ftc-test 模組中寫測試類,然後執行
mvn test -P你起的profile名

即可進行測試。但seam-2.3中預設使用TestNG而不是JUnit,所以還需要對pom檔案進行修改。直接把ftc聚合模組的pom.xml改成下面的內容即可:
<?xml version="1.0" encoding="UTF-8"?>
4.0.0cnftc1.0-SNAPSHOTpomrailway safety monitorrailway safety monitorhttp://dz.sdut.edu.cn/redmineftc-ejbftc-webftc-earftc-testsJBoss repositoryhttp://repository.jboss.org/nexus/content/groups/public/phantomjsftcslow12.01.6.17.1.1.Final0.5.8.2012071112201.6.2*firefoxproxyhttp://localhost:8080http://localhost:818014444localhost030000false${project.build.directory}/ftest-logs${project.build.directory}/ftest-output300truesrc/test/resources-ftestlocalhost/${project.build.finalName}/${env.JBOSS_HOME}/server/all${env.JBOSS_HOME}default${env.CATALINA_HOME}falseUTF-81.61.6${maven.compiler.target}${maven.compiler.source}postgresqlpostgresql9.1-901-1.jdbc44.111.1.2.Finalorg.jboss.arquillianarquillian-bom1.1.2.Finalpomimportorg.jboss.arquillian.extensionarquillian-drone-bom1.2.3.Finalpomimportorg.jboss.arquillian.seleniumselenium-bom2.39.0pomimportcn.ftcftc-ejb${project.version}ejbcn.ftcftc-web${project.version}warcn.ftcftc-ear${project.version}org.jboss.seambom2.3.0.Finalpomimportcommons-loggingcommons-logging1.1.1providedcommons-collectionscommons-collections3.2providedcom.google.guavaguava${guava.version}org.slf4jslf4j-log4j12${slf4j.version}${jdbc.groupId}${jdbc.artifactId}${jdbc.version}testjavax.enterprisecdi-apiprovidedorg.jboss.spec.javax.annotationjboss-annotations-api_1.1_specprovidedjunitjunittestorg.jboss.arquillian.junitarquillian-junit-containertestorg.jboss.arquillian.graphenegraphene-webdriver2.0.1.Finalpomtestarquillian-demomaven-compiler-plugin3.11.61.6UTF-8maven-ear-plugin2.7org.codehaus.mojobuild-helper-maven-plugin1.7maven-resources-plugin2.5org.jboss.as.pluginsjboss-as-maven-plugin7.3.Finaldeploymaven-ejb-plugin2.33.0maven-war-plugin2.1.1truefalse${project.build.finalName}firefoxfirefoxchromechromearq-jboss-as-remoteorg.jboss.asjboss-as-arquillian-container-remote7.1.1.Finaltestorg.jboss.arquillian.protocolarquillian-protocol-servlettestarq-jboss_as_managed_7.xmaven-surefire-plugin2.14.1JBOSS_AS_MANAGED_7.Xorg.jboss.asjboss-as-arquillian-container-managed7.1.1.Final

然後將ftc-test 模組中的pom.xml 檔案修改為以下內容:
<?xml version="1.0" encoding="UTF-8"?>
4.0.0ftccn1.0-SNAPSHOTcn.ftcftc-testsftc Integration Tests Module (EE6)cn.ftcftc-ejbejbtestorg.slf4jslf4j-log4j12testorg.hibernate.javax.persistencehibernate-jpa-2.0-apiorg.jboss.spec.javax.facesjboss-jsf-api_2.1_specsrc/test/resources

以上修改在後續的功能測試中會用到。