测试笔记 (四) e2e测试 (Protractor)

阅读5371评论10

一, 简介

1, e2e测试: e2e或者端到端(end-to-end)或者UI测试是一种测试方法,它用来测试一个应用从头到尾的流程是否和设计时候所想的一样。简而言之,它从一个用户的角度出发,认为整个系统都是一个黑箱,只有UI会暴露给用户。

2, Protractor: protractor是angular团队出品的一个端到端的测试框架,它可以将你的程序运行在真正的浏览器,就像一个真实的用户和它交互。

protractor支持四种BDD测试框架: Jasmine 1.3, Jasmine 2.x, Mocha, and Cucumber. 默认安装的是Jasmine 2.x。API文档地址

protractor测试主要依赖三个方面:

  • Selenium Server: 一个后端jar包,用来负责跟浏览器驱动进行通讯。
  • WebDriver browser drivers: 用来驱动浏览器打开网站,并与Selenium Server通讯.
  • WebDriver APIs: 由Selenium提供给前端测试用的相关API,protractor在此基础之上,针对angular程序的特点,提供了一些适合angular程序的API.

二, 安装与配置

以上一篇文章《测试笔记 (三) angular测试(karma + jasmine)》的文件结构为基础。

npm i protractor --save-dev     //安装在项目里
touch protractor.conf.js        //同时在根目录下新建一个配置文件

目前protractor的最新版本是2.2.0,由于它没有将其核心依赖selenium-webdriver升级到2.47.0或以上.所以暂时不支持node.js V4.0, node.js V4.0环境安装会报错. 但是其正在为升级做准备,只是时间问题. 临时解决办法: 进入到node_modules/protractor下,手动修改package.json里的selenium-webdriver版本为2.47.0, 然后在node_modules/protractor 下运行npm install, 亲测可用.

安装完protractor会有两个命令行工具,protractor 和 webdriver-manager。webdriver-manager 是一个辅助工具,他可以让Selenium Server 的实例跑起来,使用它下载必要的文件。

为了方便使用配置一下package.json文件,增加以下内容:

  "scripts":{
    "test": "mocha test",
    "test-e2e":"protractor protractor.conf.js",
    "update-webdriver":"webdriver-manager update"
  }

运行命令npm run update-webdriver 下载浏览器驱动文件.

此处需要翻墙,或者手动下载相关文件到node_modules/selenium 文件夹下.文件结构如下:

update-webdriver

配置文件内容及说明如下:

// protractor 配置
exports.config = {
  //每个运行在浏览器的脚本文件超时时间,单位毫秒.
	allScriptsTimeout: 11000,
  //使用的测试框架
  framework: 'jasmine2',
  //测试的文件路径
  specs: ['test_e2e/**/*.spec.js'],
  //程序的基本URL,protractor.get()将以它作为相为路径
  baseUrl: 'http://localhost:3000',
  //浏览器配置
  capabilities: {
    browserName: 'chrome'
  },
  //多浏览器配置
  // multiCapabilities: [{
  //   browserName: 'firefox'
  // }, {
  //   browserName: 'chrome'
  // }]
  // jasmine配置
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000
  },
  //selenium及浏览器驱动文件路径
  seleniumServerJar: 'node_modules/protractor/selenium/selenium-server-standalone-2.45.0.jar',
  chromeDriver: 'node_modules/protractor/selenium/chromedriver'
}

三, 写测试

为了让效果更加明显,我们为angular小程序增加一个路由页面.

//client/app/index.js  增加
			$stateProvider
			  .state('main', {
			    url: '/',
			    templateUrl: 'app/main.html',
			    controller: 'MainCtrl'
			  })			  
			  .state('article', {
			    url: '/article/:id',
			    templateUrl: 'app/article.html',
			    controller: 'ArticleCtrl'
			  });


		.controller('ArticleCtrl',function ($scope,$http,$stateParams) {
			$http.get('/article/'+ $stateParams.id).success(function (data, status) {
				$scope.article = data;
			}).error(function (err, status) {
				$scope.err_msg = '文章不存在!';
			});
		});

//client/app/article.html
<h1>文章内容页</h1>
<hr>
<div ng-if="article">
	<p class="title">{{article.title}}</p>
	<p class="content">{{article.content}}</p>
</div>
<div ng-if="err_msg">
	<h2 class="errmsg">{{err_msg}}</h2>
</div>
<hr>

//修改client/app/main.html
<h1>{{name}}的博客</h1>
<div ng-repeat="article in articleList">
	<p>{{article.id}}</p>
	<p>{{article.title}}</p>
	<p>{{article.content}}</p>
	<a ui-sref="article({id: article.id})">查看文章内容</a>
	<hr>
</div>

在test_e2e下增加测试文件 main.spec.js 内容如下:

describe('test-example e2e test',function() {
	beforeEach(function () {
		browser.get('/');
	});

  it('should return index page title and my name', function() {
    expect(browser.getTitle()).toBe("Angular 测试");
    expect(element(by.exactBinding('name')).isPresent()).toBe(true);
    expect(element(by.exactRepeater('article in articleList')).isPresent()).toBe(true);
    var title = element(by.repeater('article in articleList').row(0).column('article.title'));
    expect(title.getText()).toEqual('中国世界第一');
  });

  it('should return article detail page', function() {
    element.all(by.linkText('查看文章内容')).first().click();
    expect(element(by.tagName('h1')).getText()).toEqual('文章内容页');
    expect(element(by.className('title')).getText()).toEqual('中国世界第一');
    expect(element(by.className('errmsg')).isPresent()).toBe(false);
  });

  it('should return article 404 error page', function() {
  	element.all(by.linkText('查看文章内容')).last().click();
  	expect(element(by.tagName('h1')).getText()).toEqual('文章内容页');
  	expect(element(by.className('errmsg')).isPresent()).toBe(true);
  });
	  
});

输入命令运行: npm run test-e2e 看看是否有打开chrome浏览器,跳转页面,按照测试内容一步步测试.
共有三个测试用例,全部通过.
protractor API主要分为两大块:

  • browser浏览器的操作
  • DOM元素的操作
    而查找DOM元素,与其交互,然后查看交互后的状态与你的期望是否一致是protractor的核心.
    Protractor提供全局函数element和全局Locator对象By结合来获取元素,然后再使用一些操作元素的方法来和浏览器交互.比如:
element(by.tagName('h1')).getText()
by.tagName('h1')用来定位元素,作为参数提供给element,再用getText()可获得h1标签的内容.

//常用的by查找元素方法
//根据class名来查找元素
by.css(‘myclass')
//根据id来查找元素
by.id(‘myid')
//根据ng-model名来查找元素
by.model(’name')
//查找绑定了指定名的元素
by.binding(‘bindingname')
//查找指定repeater中的元素
by.repeater('article in articleList')
//准确的查找一个repeater,常用来判断是否存在
by.exactRepeater('article in articleList')

//常用的操作元素方法
//点击元素
el.click();
//给该元素输入内容
el.sendKeys(’text’);
//清空元素内内容
el.clear();
//获取指定属性的值
el.getAttribute(‘value’);
//获取元素的文本值
el.getText();
//判断元素是否存在.
el.isPresent()

注意这些方法返回的都是promise,如果进行期望判断,expect()可以获取相应值,如:

expect(element(by.tagName('h1')).getText()).toEqual('文章内容页');

否而如果是想取出它的值.则如下:

element(by.tagName('h1')).getText().then(function(value){
   //获取value值
})

element.all 用来匹配多个元素. protractor提供一些辅助函数对其进一步的筛选匹配,如: filter,get,first,last,count,each,map,reduce

API参考地址
本文测试样例下载地址

10条评论添加新评论
zanzan2016.1.17 8:26

alert("sss")

zan@zan sss

zan@zan sss

zanzan2016.1.17 8:27

alert("sss")

liu超o@zan ggg

perfectyangperfectyang2016.3.28 15:1

testest

夜神月啊啊夜神月啊啊2016.5.20 8:22

aaaaaaaaaaaaaaaaaa

苏格拉苏格拉2016.6.29 8:3

xiexie

de mengde meng2016.10.9 11:19

hao

SmokingIceSmokingIce2017.1.16 8:57

噢噢噢噢

SmokingIce@SmokingIce 寄几回复寄几

Chia JuneChia June2017.2.3 13:24

不错

mirazmiraz2017.10.30 10:1

Published

lufeverlufever2017.12.29 3:11

这是一条新的评论测试