本系列教程共五篇,分别是:
二、JBoss Forge、ShrinkWarp快速指南
四、使用 Arquillian + Drone + Selenium + Graphene 进行Web自动化测试
五、使用 Arquillian 在云端进行测试
本文所涉及到的内容有:
1. Arquillian
2. Arquillian Drone
3. Arquillian WebDriver(Selenium WebDriver)
4. Arquillian Graphene
5. ShrinkWrap
前言
开发Web应用时,最传统也是最常用的测试方法,就是构建、部署、打开浏览器、用鼠标点相关链接,最后通过人眼去看来判断功能是否正常。由于人操作的速度是远远慢于程序执行速度的,所以这种人工测试的方式其实会占用大量的时间。除此之外人还会偷懒,可能测3次、4次后就不愿意再重复这样的过程了。幸运的是,现在,我们可以使用程序代码来让这一过程自动化,即可以通过编写代码的方式来模拟人在使用浏览器时点击链接、填写表单、提交按钮,甚至是等待页面载入的过程。
在Arquillian之前,有一个名为 Selenium 的工具能够实现测试自动化,并支持Java、PHP、JavaScript、Ruby、Python等主流编程语言。但其在使用时代码量较大,过程比较繁琐(稍后将通过对比来说明这一点)。Arquillian Drone 和 Arquillian Graphene 简化了Web应用功能测试的编写,它们通过更高一层的封装,并利用Java注解的特性,减少了测试代码量。下面我们就通过实例工程来看看如何使用。
客户模式(Client Mode)简介
In the test, we’ve injected the instance of the bean, then asserted that the injection has occurred. Arquillian first enriches the archive with the test infrastructure. It then connects to the server to deploy the archive and execute the test method inside of the container by launching the JUnit test runner a second time inside that environment. Finally, Arquillian retrieves the results from that remote execution. This example demonstrates the default run mode of Arquillian: in-container. In a sense, the local JUnit runner is a client of the container, being driven by Arquillian.
The other run mode in Arquillian is the client run mode. In this mode, Arquillian deploys the test archive ‘as is’ to the container. It then allows the tests to run in the same JVM as the test runner. Now your test case is a client of the container. The test no longer runs inside the container, yet Arquillian still handles the life cycle of the container as well as deployment of the test archive. It’s the ideal mode for web UI testing.
用Arquillian写功能测试必须使用 Client Mode,其方法有两种:@Deployment(testable = false)
public static Archive<?> createDeployment() {
// ... ...
}
2. 在@Test 注解方法上增加 @RunAsClient注解。如:
@Test
@RunAsClient
public void should_run_as_client() {
// executed from the client JVM
}
其中方法2灵活性较强,因为我们可以把一部分@Test方法指定为Client Mode,另一部分不指定。如果使用方法1,那么所有的@Test都会以客户模式运行。
Graphene 和 Drone
配置依赖,以Seam项目为例
<dependencies>
<!-- arquillian and Drone -->
<dependency>
<groupId>org.jboss.arquillian</groupId>
<artifactId>arquillian-bom</artifactId>
<version>1.1.2.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-drone-bom</artifactId>
<version>1.2.3.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.selenium</groupId>
<artifactId>selenium-bom</artifactId>
<version>2.39.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
注意,顺序非常重要,务必把这3个dependency作为 dependencyManagement节点下的前3个子节点. 然后在dependencyManagement 外的 dependencies中添加以下内容:
<dependency>
<groupId>org.jboss.arquillian.graphene</groupId>
<artifactId>graphene-webdriver</artifactId>
<version>2.0.1.Final</version>
<type>pom</type>
<scope>test</scope>
</dependency>
注意,版本非常重要,如果版本号与上面不一致,很可能就会出现各种奇怪的错误。这里插一个小故事,如果把 org.jboss.arquillian:arquillian-bom:1.1.2.Final 改为 org.jboss.arquillian:arquillian-bom:1.1.3.Final,即换一个新一点的版本,那么在运行时 WebDriver 就会奇怪地扔 NullPointerExcepton异常。我在StackOverflow上提问,结果最后被证明是一个Bug, Arquillian 项目组的人看到后已经提交了Bug报告,预计会在下一个版本中修复。
编写测试代码
@Deployment(testable = false)
public static Archive<?> createDeployment() {
EnterpriseArchive er = ShrinkWrap.create(ZipImporter.class, "ftc.ear")
.importFrom(new File("../ftc-ear/target/ftc.ear")) // 将ftc.ear文件导入
.as(EnterpriseArchive.class);
WebArchive web = er.getAsType(WebArchive.class, "ftc-web.war");
web.addClasses(BeanTest.class);
return er;
}
@Drone
private WebDriver browser; // 注入 WebDriver,用来操作浏览器
@ArquillianResource
private URL url; // 得到项目部署到JBoss上时的访问地址
@FindBy(id = "username")
private WebElement username;
@FindBy(id = "password")
private WebElement password;
@FindBy(id = "submit")
private WebElement submitBtn;
@FindBy(id = "home-page-identifier")
private WebElement page;
@Test @InSequence(1)
public void isTestReady() {
Assert.assertNotNull(browser);
Assert.assertNotNull(url);
}
@Test @InSequence(2)
public void functionalTest() {
browser.get(url.toExternalForm()); // 打开浏览器,导航至刚刚部署的项目
username.sendKeys("Neo"); // 在username的input标签上输入 "Neo"
password.sendKeys("123456"); // 在密码框中输入 "123456"
Graphene.guardHttp(submitBtn).click(); // "点击" 登陆按钮
//username.submit(); // 另一种“点击”方式
Assert.assertEquals("领域知识框架构建", page.getText().trim()); // 判断是否真的导航到了home.xhtml
}
}
指定测试浏览器
<?xml version="1.0" encoding="UTF-8"?>
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://jboss.org/schema/arquillian"
xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<extension qualifier="webdriver">
<property name="browser">firefox</property> <!-- 使用firefox浏览器 -->
</extension>
</arquillian>
然后为了方便起见,我们可以在pom.xml 文件中新建多个 profile,这样在运行测试的时候只需要指定不同的profile就可以在不同的浏览器中进行测试了。
<profile>
<id>firefox</id>
<properties>
<browser>firefox</browser>
</properties>
</profile>
<profile>
<id>chrome</id>
<properties>
<browser>chrome</browser>
</properties>
</profile>
... ...
运行测试
mvn clean install -Dmaven.test.skip=true
mvn test -Parq-jbossas-remote
之后,我会们发现浏览器一闪而过,测试成功。