Arquillian测试框架快速上手教程(四)- 使用Arquillian + Drone + Selenium + Graphene 进行Web自动化测试

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

一、环境搭建、容器适配、单元测试

二、JBoss Forge、ShrinkWarp快速指南

三、使用 Arquillian 进行Java持久化测试

四、使用 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)简介

以下是官网对 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,其方法有两种:
1. 为@Deployment注解指定testable = false属性。如:
@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

Graphene是 Selenium WebDriver API的功能扩展和进一步封装,它简化了原有WebDriver API的使用。而Drone则负责管理浏览器的生命周期,即Drone负责在运行测试的时候打开浏览器,简化了初始化部分的代码,并提供多浏览器支持,比如 IE, Firefox, Chrome等。在这里我们所指的浏览器都是有UI界面的,是给用户浏览网页用的。还有一种浏览器,名为 "Headless Browser",这类浏览器没有UI界面,因此它们并不是给用户使用的,而供程序来调用,获取网页信息。PhantomJS  和 HtmlUnit 就属于 Headless Browser。

那么 Graphene 到底是如何做到模拟用户浏览器操作,如何自动启动和关闭浏览器的呢?在Selenium WebDirver 1.0的时候,它是通过生成JavaScript代码来实现操作模拟功能的,现在WebDriver已经升级到了2.0, 其工作原理是调用浏览器本身提供的编程接口来实现功能,因此它的行为会由浏览器的不同而不同。Graphene基本上屏蔽了代码上的区别,提供了统一的编程接口。不过要在不同的浏览器上测试,就要下载对应版本的Driver,这一点类似于JDBC。

配置依赖,以Seam项目为例

如果在读第一篇教程的时候遵行了最后的那2个pom.xml文件,那么这里就不需要再做改动了。如果没有,则需按以下步骤进行配置。
向dependencyManaged节点中加入以下内容:

<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报告,预计会在下一个版本中修复。 

下面我们就可以开始 自动化测试了。

编写测试代码

首先要说明的是,因为我们是在做功能测试,是在测试整个Web应用的流程是否正确,那么就不能跟以前一样只是把用到的class打包进行测试了,而是需要将整个项目完全打包,部署,然后再测试。我们先将整个工程构建完成,然后使用ShrinkWarp 的 importer,将构建好的ear包“导入”,再进行部署。代码如下:
@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
	}
}

说明:
1. @FindBy的作用是根据指定的标识符从当前页面中查找元素,然后封装成WebElement对象并注入到类成员中。@FindBy功能非常强大,它可以通过标签的id, name来查找元素,还可以通过CSS类名、标签名、<a>标签的链接地址、CSS选择器甚至JQuery选择器来获取元素。(碉堡了)
2. @Drone的作用是注入一个代表了当前浏览器的WebDriver,通过这个对象我们可以控制浏览器的行为。
3. @ArquillianResource标在URL类上时,会将项目部署到JBoss后实际的访问地址注入进来。
4. 当执行到 browser.get()方法时,浏览器就会自动被打开,并导航至指定的页面。
5. 调用WebElement的sendKeys()方法可以向标签发送键盘消息,这里是输入了几个字符。
6. WebElement的submit()方法会自动确定当前元素所在的表单,找到提交按钮并触发"click"动作。如果当前表单没有submit按键的话,该方法会扔异常。

既然submit()方法能这么方便地提交表单,那上面为什么要用 Graphene.guardHttp()来触发点击动作呢?这样做的是为了同步(synchronization)。我们知道,在用户点击 登陆 后,用户输入的信息会被发送到服务器,服务器应用程序会调用相应的方法来验证用户信息的正确性。但这一过程是需要时间的,可能一瞬间就完成了,也可能要过上2、3秒才能完成。所以,guardHttp()方法的作用即是保证页面的同步性,只有当服务器完成验证,发回响应页面,并且响应页面完全载入完成时,该方法才会返回。否则的话,页面还没有打开就执行下面的代码,显然会导致测试失败。


指定测试浏览器

现在我们需要通知 Arquillian 我们到底要用哪个浏览器运行测试。前面提到 arquillian.xml 是用来配置arquiillian相关属性的,这个任务自然也就要交给它了。在 src/test/resources目录创建arquillian.xml文件,内容如下:
<?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>
         ... ...



运行测试

切换到ftc主目录,执行:
mvn clean install -Dmaven.test.skip=true
mvn test -Parq-jbossas-remote

之后,我会们发现浏览器一闪而过,测试成功。

这篇文章仅仅是为了演示最基本的配置和功能,起到抛砖引玉的作用。关于WebDriver更多更强大的用法,请参见 Selenium Documentation

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。