这是第一个“番外篇”,基于为Maven JavaEE7系列博客 “搭建”的演示项目。我们已经定义了一个坚实的基础结构和一些模块。在应用程序中,一般使用Arquillian(+JUnit)这个完美的框架。在进行单元测试和EJB服务时我们能够使用“真实”的应用服务,这个服务几乎与将要部署的服务一模一样。实际上,我看了一些在这里找到的基础设置指南。与指南不同,我将使用Wildfly 8.1 作为单元测试的嵌入式容器。Wildfly 8.1是一个十分成熟的JavaEE7容器,使我能够安全地测试所有特性。
Arquillian思想和Maven
为了在Maven化项目中使用Arquillian,你需要了解最基本的事情就是遵循以下术语(概念)。这些概念会被定义为各种依赖:
- 你需要Arquillian框架、库。想象一下,一台新的轿车却没有发动机,那么前面的工作都是无意义的。
- 你需要Arquillian容器适配器(Container Adapter)。设想你需要在你的车前安装占位装置(placeholder),比如框架以便发动机能够安装其中。
- 你需要真正的容器(应用程序服务器)。这就是我们将要安装适合我们汽车的发动机(engine)。
- 你需要JUnit。这就是你的汽车将要被测试所跑的“测试跑道(Test Track)”。
- 你需要代码(EJBs)。这些就是你将要被测试的汽车所要搭载的乘客。
定义父pom的依赖关系
正如我们在前面四篇文章中描述的,父pom是定义依赖关系和应用程序所使用库版本的地方。考虑到上面提到的术语,让我们开始修改父pom中的dependencyManagement。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
<
junit-version
>4.11</
junit-version
>
<
arquillian-version
>1.1.4.Final</
arquillian-version
>
<
arquillian-wildfly-version
>8.1.0.CR2</
arquillian-wildfly-version
>
<
arquillian-transaction-version
>1.0.1.Final</
arquillian-transaction-version
>
</
properties
>
<
dependencyManagement
>
<
dependencies
>
<
dependency
>
<
groupId
>javax</
groupId
>
<
artifactId
>javaee-api</
artifactId
>
<
version
>${javaee-api-version}</
version
>
</
dependency
>
<!-- -JUNIT-->
<
dependency
>
<
groupId
>junit</
groupId
>
<
artifactId
>junit</
artifactId
>
<
version
>${junit-version}</
version
>
</
dependency
>
<!-- rquillian itself-->
<
dependency
>
<
groupId
>org.jboss.arquillian</
groupId
>
<
artifactId
>arquillian-bom</
artifactId
>
<
version
>${arquillian-version}</
version
>
<
scope
>import</
scope
>
<
type
>pom</
type
>
</
dependency
>
<!-- this is in an extention to arquillian it is optional-->
<
dependency
>
<
groupId
>org.jboss.arquillian.extension</
groupId
>
<
artifactId
>arquillian-transaction-bom</
artifactId
>
<
version
>${arquillian-transaction-version}</
version
>
<
type
>pom</
type
>
<
scope
>import</
scope
>
</
dependency
>
<!-- this is container adapter for wildfly-->
<
dependency
>
<
groupId
>org.wildfly</
groupId
>
<
artifactId
>wildfly-arquillian-container-embedded</
artifactId
>
<
version
>${arquillian-wildfly-version}</
version
>
</
dependency
>
<!-- this is the wildfly emb.container - BUT eventually it is not a fully blown emb.container-->
<
dependency
>
<
groupId
>org.wildfly</
groupId
>
<
artifactId
>wildfly-embedded</
artifactId
>
<
version
>${arquillian-wildfly-version}</
version
>
</
dependency
>
</
dependencies
>
</
dependencyManagement
>
|
对上面代码片段的说明:
- 一些依赖是pom类型和import域(import scope)。实际上,这是在定义一组依赖中的特例。pom类型的依赖,意思是说这是由一组独立库组合而成的。只需要定义这个超级pom,就会继承这些包含其中的各个依赖。在Maven术语中,这样一组依赖被称为BOM或材料清单(Bill of Materials)。Arquillian由若干具体的库和依赖构成,不用逐个义。而使用arquillian-pom定义能够达到同样的效果。
- “arquillian-transaction-bom”是可选依赖,可以不定义。它在测试中可以增加额外的特性,这其中最有名的就是@Transactional arquillian注解。可以在这里或这里here查更多信息。
- Wildfly和JBoss是例外,需要使用“wildfly-embedded”标记依赖。假设这是个Wildfly应用服务器“嵌入的(embedded)”Uber jar版本,Glassfish就是如此。最后,这是人们尝试在Wildfly中安装Arquillian常见的错误。为了使整个工作运转,你需要下载“真实的”应用服务器。请继续看下面部分,会有助于解决这个特殊问题。
(译注,Uber Jar在一个Jar中包含了你的Jar包及所有依赖。关于Uber Jar请参见这里)
为我们的EJB模块配置Arquillian和测试
在示例程序中,我们已经在名为sample-ejb的模块中编写了大部分EJB服务,因此我们需要为pom添加额外的配置工作,以便于在模块测试中使用junit+Arquillian。
这个pom的绝大部分的配置工作,是为了适应Wildfly的特殊情况。为了在测试阶段使所有机制正常运转,需要下载Wildfly.zip(可以从浏览器下载),解压到某个位置,并指定Arquillian路径。一旦完成,Arquillian将会接管所有工作。
首先,下载wildfly服务器
下面sample-services pom中写的配置信息,是我们的“EJB服务”模块:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<
plugin
>
<
artifactId
>maven-dependency-plugin</
artifactId
>
<
executions
>
<
execution
>
<
id
>unpack</
id
>
<
phase
>process-test-classes</
phase
>
<
goals
>
<
goal
>unpack</
goal
>
</
goals
>
<
configuration
>
<
artifactItems
>
<
artifactItem
>
<
groupId
>org.wildfly</
groupId
>
<
artifactId
>wildfly-dist</
artifactId
>
<
version
>8.1.0.Final</
version
>
<
type
>zip</
type
>
<
overWrite
>false</
overWrite
>
<
outputDirectory
>target</
outputDirectory
>
</
artifactItem
>
</
artifactItems
>
</
configuration
>
</
execution
>
</
executions
>
</
plugin
>
|
请注意在上面配置中,
- 我们使用maven-dependency-plugin。
- 我们指明plugin在Maven生命周期的process-test-classes阶段生效。当开始生效时,去执行“unpack”目标(goal)。因此,在Maven启动之前,运行上面的测试会下载并解压Wildfly 8.1到classpath。
使用maven-surfire插件运行测试
下面代码是sample-services.pom的一部分。配置了Maven Serefire Plugin,该插件实际执行JUnit-Arquillian测试。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<
plugin
>
<
groupId
>org.apache.maven.plugins</
groupId
>
<
artifactId
>maven-surefire-plugin</
artifactId
>
<
configuration
>
<!-- Fork every test because it will launch a separate AS instance -->
<
forkMode
>always</
forkMode
>
<
systemPropertyVariables
>
<
java.util.logging.manager
>org.jboss.logmanager.LogManager</
java.util.logging.manager
>
<
jboss.home
>${project.basedir}/target/wildfly-8.1.0.Final</
jboss.home
>
<
module.path
>${project.basedir}/target/wildfly-8.1.0.Final/modules</
module.path
>
</
systemPropertyVariables
>
<
redirectTestOutputToFile
>false</
redirectTestOutputToFile
>
/configuration>
</
plugin
>
|
上面的配置中:
- Surefire提供了单元测试的运行环境。在我们的例子中,使用JUnit-Arquillian驱动测试。为了使Arquillian能够正确的初始化并识别需要作为系统参数的容器,切记wildfly、jboss是一个特殊情况,容器将会被下载到输出或目标文件夹。
在sample-services模块中添加必要的依赖关系
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<
dependency
>
<
groupId
>junit</
groupId
>
<
artifactId
>junit</
artifactId
>
<
scope
>test</
scope
>
</
dependency
>
<
dependency
>
<
groupId
>org.jboss.arquillian.junit</
groupId
>
<
artifactId
>arquillian-junit-container</
artifactId
>
<
scope
>test</
scope
>
</
dependency
>
<
dependency
>
<
groupId
>org.wildfly</
groupId
>
<
artifactId
>wildfly-arquillian-container-embedded</
artifactId
>
<
scope
>test</
scope
>
</
dependency
>
<
dependency
>
<
groupId
>org.wildfly</
groupId
>
<
artifactId
>wildfly-embedded</
artifactId
>
<
scope
>test</
scope
>
</
dependency
>
<
dependency
>
<
groupId
>org.jboss.arquillian.extension</
groupId
>
<
artifactId
>arquillian-transaction-jta</
artifactId
>
<
scope
>test</
scope
>
</
dependency
>
|
创建示例测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
package
gr.javapapo;
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;
import
javax.ejb.EJB;
/**
* Created by papo on 5/31/14.
*/
@RunWith
(Arquillian.
class
)
public
class
DemoArquillianTest {
@EJB
UserServices dummyService;
@Deployment
public
static
JavaArchive createDeployment() {
return
ShrinkWrap.create(JavaArchive.
class
)
.addClass(UserServices.
class
)
.addAsManifestResource(EmptyAsset.INSTANCE,
"beans.xml"
);
}
@Test
public
void
testSaysHello() {
Assert.assertEquals(
"hello"
,dummyService.sayHello());
}
}
|
完成
在sample-parent文件夹下,输入:
1
|
mvn clean packege
|