如何进行前端如何自动化测试试

推荐这篇日记的豆列
&&&&&&&&&&&&前端自动化单元测试初探 - 简书
前端自动化单元测试初探
本篇文章是我在学习前端自动化单元测试时的一些思路整理,之前也从未接触过单元测试相关工具,如有错漏,请读者斧正。要是觉得不专业...你打我呀~~~示例代码的github地址:
1. 什么是单元测试
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。——百度百科
对于JavaScript来说,通常也是针对函数、对象和模块的测试
2. 为什么要进行单元测试
经验表明一个尽责的单元测试方法将会在软件开发的某个阶段发现很多的Bug,并且修改它们的成本也很低。在软件开发的后期阶段,Bug的发现并修改将会变得更加困难,并要消耗大量的时间和开发费用。无论什么时候作出修改都要进行完整的回归测试,在生命周期中尽早地对软件产品进行测试将使效率和质量得到最好的保证。在提供了经过测试的单元的情况下,系统集成过程将会大大地简化。开发人员可以将精力集中在单元之间的交互作用和全局的功能实现上,而不是陷入充满很多Bug的单元之中不能自拔。——百度百科
3. 如何进行单元测试
3.1 选择测试工具
在JavaScript世界中,我们需要至少三个工具来进行单元测试,这意味着每个工具都需要你进行选择:
测试管理工具测试管理工具是用来组织和运行整个测试的工具,它能够将测试框架、断言库、测试浏览器、测试代码和被测试代码组织起来,并运行被测试代码进行测试。测试工具有很多选择,Selenium、WebDriver/Selenium 2、Mocha、JsTestDriver、HTML Runners和Karma,我这里选择使用Karma。(关于它们的对比,可以看看这篇文章:)
测试框架测是框架是单元测试的核心,它提供了单元测试所需的各种API,你可以使用它们来对你的代码进行单元测试。JavaScript的测试框架可谓百花齐放,选择太多了(可以参考),我这里选择使用Mocha(关于它们中一些框架的对比,可以参考)
断言库断言库提供了用于描述你的具体测试的API,有了它们你的测试代码便能简单直接,也更为语义化,理想状态下你甚至可以让非开发人员来撰写单元测试。当然,你也完全可以不使用断言库,而是用自己的测试代码去测试,不过几乎没有人会这么干,除非你自己实现了一个测试断言库。测试断言库的选择也不少:better-assert、should.js、expect.js、chai.js等等(有关它们的对比,可以参考)我这里选择chai.js。
有了上面的三个工具,你就可以开始对你的node代码进行测试了。但是如果想要对前端代码进行测试,还需要另外一个工具:
测试浏览器前端代码是运行在浏览器中的,要对其进行单元测试,只能将其运行在浏览器上。目前大部分测试工具都支持调用和运行本地浏览器来进行测试,但如果你的测试仅仅是针对函数和模块的单元测试,则完全可以使用一款无界面的浏览器:PhantomJs
另外,还有一个很重要的事情就是测试覆盖率的统计。一般情况下你的测试管理工具会提供相关的覆盖率统计工具,但是有些情况下它们提供的工具未必是你想要的。比如当被测试的代码是经过了某些打包工具打包完了且被压缩和混淆了,同时打包工具还混入了很多自己的代码,这时覆盖率的统计就容易不准确。所以为了避免这种情况,测试覆盖率统计工具需要谨慎选择,至少你得确认它支持你的打包工具已经打包好的代码。
测试覆盖率统计工具Karma-Coverage是Karma官方提供的覆盖率统计插件,自然成为项目的首选。
至此,我们需要的工具已经完备了,下面是选择好的工具清单:
测试管理工具:Karma
测试框架:Mocha
断言库:Chai
测试浏览器:PhantomJs
测试覆盖率统计工具:Karma-Coverage
3.2 构建一个最基本的测试
3.2.1 配置好你的npm
初始化项目的package.json,并将需要的工具安装到项目中,安装完成后pakeage.json的devDependencies中应当出现下面的这些工具
"devDependencies": {
"chai": "^3.5.0",
"karma": "^1.3.0",
"karma-chai": "^0.1.0",
"karma-coverage": "^1.1.1",
"karma-mocha": "^1.1.1",
"karma-phantomjs-launcher": "^1.0.2",
"mocha": "^3.0.2"
3.2.2 初始化Karma配置文件
在项目的根目录运行
karma init
初始化Karma配置文件:
初始化Karma配置文件
生成的karma.conf.js只是最基本的karma配置,我们还需要手动修改一些地方。在其中的frameworks一项中增加chai
frameworks: ['mocha','chai'],
然后在config.set({})中添加:
plugins : [
'karma-mocha',
'karma-chai',
'karma-phantomjs-launcher'
3.2.3 提供需要测试的代码并编写测试代码
在上文的初始化Karma配置时,已经告诉Karma,需要被测试的代码和测试代码放在src/和test/文件夹中,所以我们应该在src/文件夹下提供要被测试的代码,在test/文件夹下提供测试代码:
项目文件结构
在src/文件夹中新建index.js文件,在这个文件中添加两个非常简单的函数:
function isNum (num) {
return typeof num === 'number'
function isString (str) {
return typeof str === 'string'
然后在test/文件夹中新建index.test.js文件。通常,测试脚本与所要测试的源码脚本同名,但是后缀名为.test.js(表示测试)或者.spec.js(表示规格)。在该文件中开始编写测试代码:
describe('index.js的测试', function () {
it('1应该是数字', function() {
// expect(isNum(1)).to.be.true
isNum(1).should.equal(true)
it('"1" 应该是字符', function() {
// expect(isString('1')).to.be.true
isString('1').should.equal(true)
编写测试文件时,describe、it都是由mocha提供的测试用api:
describe块称为"测试套件"(test suite),表示一组相关的测试。它是一个函数,第一个参数是测试套件的名称("index.js的测试"),第二个参数是一个实际执行的函数。
it块称为"测试用例"(test case),表示一个单独的测试,是测试的最小单位。它也是一个函数,第一个参数是测试用例的名称("1应该是数字"),第二个参数是一个实际执行的函数。——
如果测试不通过,测试套件和测试用例的描述都会在命令行输出,告诉你哪里测试失败了。被测试代码和测试代码编写完毕后,在项目根目录输入:
karma start
运行成功后,测试结果便会显示在命令行中。并且这时你修改任意代码,单元测试便会在你保存后自动运行。
3.2.4 统计测试覆盖率
单元测试很多时候需要统计测试覆盖率。使用karma-coverage来统计你的单元测试覆盖率。修改karma.conf.js:
preprocessors: {
'src/*.js': ['coverage']
reporters: ['progress', 'coverage'],
然后再运行karma start,你的项目中便会多出一个coverage文件夹,文件夹中按照浏览器分了覆盖率统计结果,我们使用的是PhantomJs,自然会有一个PhantomJs ..*文件夹,用浏览器打开index.html便可查看测试覆盖率。
3.3 集成webpack
很多时候,项目中会用到webpack来进行打包,有了Webpack我们可以使用ES6甚至ES7语法,可以轻松打包Vue、React、Angular等主流框架,可以有Eslint代码检查。所以将Webpack集成进Karma后,我们可以使用最新的JS语法来编写测试代码,也可以对使用了主流框架的代码进行单元测试了。
这里我们以使用ES6语法为目的,来演示如何集成Webpack。
3.3.1 安装Webpack和Babel
首先安装Webpack和karma-webpack插件
npm install webpack karma-webpack --save-dev
然后安装babel
npm i --save-dev babel-loader babel-core babel-preset-es2015
3.3.2 在Karma中配置和使用Webpack
修改karma.conf.js,将webpack添加进去。
3.3.2.1 设置需要Webpack打包的文件
在preprocessors中告诉karma需要Webpack打包的文件所在位置,这里我想同时在被测试代码和测试代码中使用ES6语法,那么理论上我除了将被测试代码位置告诉Webpack之外,还需要将测试代码的位置也告诉Webpack。
但如果你的代码是模块化的,使用了ES6的模块系统,那么即使你将已经模块化的index.js打包并好并注入到浏览器也是没有用的,所以正确的做法应该是在你的测试代码也就是index.test.js中引入index.js模块进行测试。然而Webpack在处理index.test.js时会查找它的引用并自动打包过来,所以如果你的被测试代码是模块化的,Karma配置中的preprocessors中就应当去掉Webpack对被测试代码的处理,同时files中也不需要让Karma将被测试代码放到浏览器了,这一切应当都交给Webpack来做:
preprocessors: {
// 'src/*.js': ['webpack', 'coverage'],
'src/*.js': ['coverage'],
'test/*.js': ['webpack']
// './src/*.js',
'./test/*.js'
3.3.2.2 配置好Webpack
在Karma中写好Webpack的配置:
// webpack config
webpack: {
loaders: [{
test: /\\.js$/,
loader: 'babel',
exclude: /node_modules/,
presets: ['es2015']
这一步有三点需要注意:
上面这些配置,完全可以独立出来成为一个webpack.test.config.js,怎么样,是不是很眼熟?
你可能已经注意到Webpack的配置中没有entry,也没有output,因为在Karma的preprocessors中已经告诉了Webpack需要打包哪些文件了,同时Karma也会处理好打包后文件的去向(当然是注入浏览器了,还能去哪,别忘记了还有karma-webpack这个插件在起作用)
测试的Webpack配置除了上面说的入口和出口,其余的配置跟普通使用Webpack没有本质区别,所以从这里你完全可以发散思维,用Webpack去做你想做的~
3.3.2.3 添加karma-webpack插件
别忘记新版的Karma几乎所有的工具都需要插件支持,这在老版本中是不需要的。所以得把karma-webpack添加到Karma的plugins中去
plugins : [
'karma-mocha',
'karma-chai',
'karma-phantomjs-launcher',
'karma-coverage',
'karma-webpack'
3.3.2.4 在你的被测试代码和测试代码中使用ES6语法
首先是被测试代码
function isNum (num) {
return typeof num === 'number'
function isString (str) {
return typeof str === 'string'
export default {
然后是测试代码
import Index from '../src/index'
console.log('开始测试')
describe('index.js的测试', function () {
it('1应该是数字', function() {
// expect(isNum(1)).to.be.true
Index.isNum(1).should.equal(true)
it('"1" 应该是字符', function() {
// expect(isString('1')).to.be.true
Index.isString('1').should.equal(true)
我这里使用了ES6 中的模块写法,在index.js中输出了一个带有两个方法的模块,这时测试代码中就需要引入这个模块了,因为仅仅是简单地将index.js输出到浏览器是不会起任何作用的(webpack打包后,两个需要测试的函数已经是私有变量了,前文也有所提及)。
这时再运行karma start,便能看到测试通过的结果,说明我们成功使用了webpack编译了ES6。现在检查一下代码覆盖率:
异常的代码覆盖率
会发现代码覆盖率无法正常检测了。即使你注释掉某个函数的测试用例,代码覆盖率仍旧是100%。这就是前文提到的,如果使用karma-coverage检测Webpack打包后的代码,就会出现这种情况。所以这里我们需要使用其它办法来检测代码覆盖率。
一般代码覆盖率的检测是需要统计被测试代码中需要测试的量,比如函数、行数等信息,然而打包后的代码因为被混入了很多别的代码,或者是变量被私有化了,这些统计就会出问题。所以最好的办法是在打包之前进行统计。
方案其实有很多,比如isparta、isparta-instrumenter-loader、istanbul。这里选择istanbul,因为karma-coverage用的就是它。同时,babel提供了一个插件babel-plugin-istanbul,能够在babel编译之前instrument你的ES6代码,可以像下面这样使用(参考):首先安装babel-plugin-istanbul:
npm install babel-plugin-istanbul --save-dev
然后将其放入到babel的插件选项中:
loaders: [{
test: /\\.js$/,
loader: 'babel',
exclude: /node_modules/,
presets: ['es2015'],
plugins: ['istanbul']
这里需要注意的是:
Note: This plugin does not generate any report or save it only adds instrumenting code to your JavaScript source code.To integrate with testing tools, please see the Integrations section.—— cnpm babel-plugin-istanbul
这个插件的功能仅仅是instrument,不生成报告,所以报告的生成还是需要karma-coverage来完成的,所以之前有关karma-coverage的设置只需要将instrument部分也就是karma.conf.js中的preprocessors中的coverage去掉即可:
preprocessors: {
// 'src/*.js': ['webpack', 'coverage'],
// 'src/*.js': ['coverage'],
'test/*.js': ['webpack']
这时再次运行karma start,便能看到测试通过的结果,说明我们成功使用了webpack编译了ES6。现在检查一下代码覆盖率:
正常的代码覆盖率
已经恢复正常了!按照上面的思路,我们完成了将Webpack配置到Karma中的工作,所以现在你可以使用Webpack来统一管理你的被测试代码和测试代码了。
4. 其它注意事项
4.1 关于npm
正常情况下国内是需要翻墙才能使用npm的,但你有两个选择:翻墙或者使用cnpm。我建议使用cnpm,安装使用可以去查看详细教程(非常简单)
4.2 关于测试框架mocha和断言库chai.js
一个咖啡一个茶,虽然你已经能够将它们运用到你的构建体系中去了,但这两者的详细API还是需要去熟悉和了解的,否则也没办法写出高质量的测试代码mocha除了可以去看英文文档之外,还可以参考我翻译的中文文档:chai.js则只需要去看API文档,我也翻译了TDD部分的API文档:
4.3 关于BDD与TDD
BDD是行为驱动开发,TDD是测试驱动开发。但其实可以认为BDD是TDD的一个子集或分支,是测试驱动开发的升级版。具体可以参考这几篇文章:
[1]:Mocha既是测试工具,也是测试框架,其实有不少测试工具既是管理工具,也是测试框架博客分类:
&& 项目上使用了selenium进行界面的自动化测试,我拿到框架比较老,只能支持FIREFOX3.6的版本,而且不能运行在WIN7的环境上,于是下载了最新的server端和client端.
&& 下载的地址可以去官网:
&&
&& SERVER端的JAR包名字: selenium-server-standalone-2.28.0.jar
&& CLIENT端的JAR包名字: selenium-java-2.28.0.zip
&& 运行环境包括下面几个文件夹:
&& lib&&& //里面主要放CLIENT端的JAR和它的依赖包,老版本的依赖包很少,新版本的很多
&&
&& test&&& //放写好的JAVA类, 里面可以方一个或者多个
&& build& //放生成CLASS文件
&& report //放跑完的结果
&& tools& //放工具等
&& build.xml& //ant脚本,编译JAVA文件,生成CLASS,路径等等
&& log.txt&&& //放LOG日志的
&& build.bat& //client端的启动
&& start-selenium-server.bat& //server端的启动&&&
&& 这个运行环境可以将写好的一个或多个JAVA文件编译并运行,模拟测试人员在界面上的各项操作,达到自动化测试的目的,最后可以生成可视化的结果.
&& (目前唯一的问题是:不能进行SSL的测试,网上找了一些办法,貌似都不能解决问题,但是估计是和项目的安全证书生成有关联)
&&
环境的配置:
1.需要修改下面三个BAT文件里面关于FIREFOX路径的设置
Test Automatics/start-selenium-server.bat
Test Automatics/tools/ start.bat
Test Automatics/tools/selenium-server/start.bat
(Firefox的路径在windowXP和win7下面不一样的)
WindowXP为firefox的安装全路径 如: C:\document and setting\administrator\Mozilla\Firefox\Profiles\rxzej817.default
Win7为参数路径, 如%APPDATA%\Mozilla\Firefox\Profiles\rxzej817.default(在运行里面输入%APPDATA%就可以找到你本地的路径)
2. JAVA_HOME的设置,我就不在这里罗嗦了
3. URL,用户名和密码的设置
&& lib\selenium-client-java-driver.jar 我在里面放了一个配置文件LocalConfig.properties里面有URL 用户名和密码的配置, 可以按照袭击的需求修改
项目的运行
先运行start-selenium-server.bat, 得到如下的结果:
再运行同级目录下的build.bat
(每个CASE如果有错误就会在控制台上打出)
错误的查看
log.txt是记录生成LOG的地方
报告的生成
最后会把所有的TEST CASE的结果放在report路径下面一个新建文件夹里面,文件夹的名字是REPORT-{时间戳},进入最里面找到INDE.HTML查看结果
新版和老版的代码区别
老版代码需要继承SeleneseTestCase类,如下:
public class TestLoginSample extends SeleneseTestCase{
public void setUp() throws Exception {
String url = LocalConfig.get("URL");
selenium = new DefaultSelenium(LocalConfig.get("DefaultSelenium_Domain"),
Integer.parseInt(LocalConfig.get("DefaultSelenium_Port")),
LocalConfig.get("DefaultSelenium_Type"),
selenium.start();
新版的代码使用JUNIT,只需要继承TestCase,如下:
public class TestLoginSample extends TestCase {
public void setUp() throws Exception {
String url = LocalConfig.get("URL");
selenium = new DefaultSelenium(
LocalConfig.get("DefaultSelenium_Domain"),
Integer.parseInt(LocalConfig.get("DefaultSelenium_Port")),
LocalConfig.get("DefaultSelenium_Type"), url);
selenium.start();
(以前写的代码必须更新了....)
浏览: 259240 次
来自: 成都
谢谢,这个文章解决了我的疑问
&bean id=&st ...
学习ing,多谢分享!
yybray 写道帅哥,为什么我配置了还是有乱码呢?你把你的s ...
帅哥,为什么我配置了还是有乱码呢?
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'Angular.Js的自动化测试详解
投稿:daisy
字体:[ ] 类型:转载 时间:
当Angular项目的规模到达一定的程度,就需要进行测试工作了。为什么要自动化测试?1,提高产出质量。2,减少重构时的痛。反正我最近重构多了,痛苦经历多了。3,便于新人接手。下面这篇文章就给大家详细介绍了Angular.Js的自动化测试,有需要的朋友们可以参考借鉴。
本文着重介绍关于ng的测试部分,主要包括以下三个方面:
框架的选择(Karma+Jasmine)
测试的分类和选择(单元测试 + 端到端测试)
在ng中各个模块如何编写测试用例
下面各部分进行详细介绍。
测试的分类
在测试中,一般分为单元测试和端到端测试,单元测试是保证开发者验证代码某部分有效性的技术,端到端(E2E)是当你想确保一堆组件能按事先预想的方式运行起来的时候使用。
其中单元测试又分为两类: TDD(测试驱动开发)和BDD(行为驱动开发)。
下面着重介绍两种开发模式。
TDD(测试驱动开发 Test-driven development)是使用测试案例等来驱动你的软件开发。
如果我们想要更深入点了解TDD,我们可以将它分成五个不同的阶段:
&&&& 首先,开发人员编写一些测试方法。
&&&& 其次,开发人员使用这些测试,但是很明显的,测试都没有通过,原因是还没有编写这些功能的代码来实际执行。
&&&& 接下来,开发人员实现测试中的代码。
&&&& 如果开发人员写代码很优秀,那么在下一阶段会看到他的测试通过。
&&&& 然后开发人员可以重构自己的代码,添加注释,使其变得整洁,开发人员知道,如果新添加的代码破坏了什么,那么测试会提醒他失败。
其中的流程图如下:
TDD的好处:
&&&& 能驱使系统最终的实现代码,都可以被测试代码所覆盖到,也即“每一行代码都可测”。
&&&& 测试代码作为实现代码的正确导向,最终演变为正确系统的行为,能让整个开发过程更加高效。
BDD是(行为驱动开发 Behavior-Driven Development)指的是不应该针对代码的实现细节写测试,而是要针对行为写测试。BDD测试的是行为,即软件应该怎样运行。
&&&& 和TDD比起来,BDD是需要我们先写行为规范(功能明细),在进行软件开发。功能明细和测试看起来非常相似,但是功能明细更加含蓄一些。BDD采用了更详细的方式使得它看起来就像是一句话。
&&&& BDD测试应该注重功能而不是实际的结果。你常常会听说BDD是帮助设计软件,而不是像TDD那样的测试软件。
最后总结:TDD的迭代反复验证是敏捷开发的保障,但没有明确如何根据设计产生测试,并保障测试用例的质量,而BDD倡导大家都用简洁的自然语言描述系统行为的理念,恰好弥补了测试用例(即系统行为)的准确性。
测试框架选择
利用karma和jasmine来进行ng模块的单元测试。
&&&& Karma:是一个基于Node.js的JavaScript测试执行过程管理工具,这个测试工具的一个强大特性就是,它可以监控(Watch)文件的变化,然后自行执行,通过console.log显示测试结果。
&&&& jasmine是一个行为驱动开发(BDD)的测试框架,不依赖任何js框架以及dom,是一个非常干净以及友好API的测试库.
karma是一个单元测试的运行控制框架,提供以不同环境来运行单元测试,比如chrome,firfox,phantomjs等,测试框架支持jasmine,mocha,qunit,是一个以nodejs为环境的npm模块.
Karma从头开始构建,免去了设置测试的负担,集中精力在应用逻辑上。会产生一个浏览器实例,针对不同浏览器运行测试,同时可以对测试的运行进行一个实时反馈,提供一份debug报告。
测试还会依赖一些Karma插件,如测试覆盖率Karma-coverage工具、Karman-fixture工具及Karma-coffee处理工具。此外,前端社区里提供里比较丰富的插件,常见的测试需求都能涵盖到。
安装测试相关的npm模块建议使用—-save-dev参数,因为这是开发相关的,一般的运行karma的话只需要下面两个npm命令:
npm install karma --save-dev
npm install karma-junit-reporter --save-dev
然后一个典型的运行框架通常都需要一个配置文件,在karma里可以是一个karma.conf.js,里面的代码是一个nodejs风格的,一个普通的例子如下:
module.exports = function(config){
config.set({
// 下面files里的基础目录
basePath : '../',
// 测试环境需要加载的JS信息
'app/bower_components/angular/angular.js',
'app/bower_components/angular-route/angular-route.js',
'app/bower_components/angular-mocks/angular-mocks.js',
'app/js/**/*.js',
'test/unit/**/*.js'
// 是否自动监听上面文件的改变自动运行测试
autoWatch : true,
// 应用的测试框架
frameworks: ['jasmine'],
// 用什么环境测试代码,这里是chrome`
browsers : ['Chrome'],
// 用到的插件,比如chrome浏览器与jasmine插件
plugins : [
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-jasmine',
'karma-junit-reporter'
// 测试内容的输出以及导出用的模块名
reporters: ['progress', 'junit'],
// 设置输出测试内容文件的信息
junitReporter : {
outputFile: 'test_out/unit.xml',
suite: 'unit'
运行时输入:
karma start test/karma.conf.js
jasmine是一个行为驱动开发的测试框架,不依赖任何js框架以及dom,是一个非常干净以及友好API的测试库.
以下以一个具体实例说明test.js:
describe("A spec (with setup and tear-down)", function() {
beforeEach(function() {
afterEach(function() {
it("is just a function, so it can contain any code", function() {
expect(foo).toEqual(1);
it("can have more than one expectation", function() {
expect(foo).toEqual(1);
expect(true).toEqual(true);
&&&& 首先任何一个测试用例以describe函数来定义,它有两参数,第一个用来描述测试大体的中心内容,第二个参数是一个函数,里面写一些真实的测试代码
&&&& it是用来定义单个具体测试任务,也有两个参数,第一个用来描述测试内容,第二个参数是一个函数,里面存放一些测试方法
&&&& expect主要用来计算一个变量或者一个表达式的值,然后用来跟期望的值比较或者做一些其它的事件
&&&& beforeEach与afterEach主要是用来在执行测试任务之前和之后做一些事情,上面的例子就是在执行之前改变变量的值,然后在执行完成之后重置变量的值
开始单元测试
下面分别以控制器,指令,过滤器和服务四个部分来编写相关的单元测试。项目地址为angular-seed(点我)项目,可以下载demo并运行其测试用例。
demo中是一个简单的todo应用,会包含一个文本输入框,其中可以编写一些笔记,按下按钮可以将新的笔记加入笔记列表中,其中使用notesfactory封装LocalStorage来储存笔记信息。
先介绍一下angular中测试相关的组件angular-mocks。
了解angular-mocks
在Angular中,模块都是通过依赖注入来加载和实例化的,因此官方提供了angular-mocks.js测试工具来提供模块的定义、加载,依赖注入等功能。
其中一些常用的方法(挂载在window命名空间下):
angular.mock.module: module用来加载已有的模块,以及配置inject方法注入的模块信息。具体使用如下:
beforeEach(module('myApp.filters'));
beforeEach(module(function($provide) {
$provide.value('version', 'TEST_VER');
该方法一般在beforeEach中使用,在执行测试用例之前可以获得模块的配置。
angular.mock.inject: inject用来注入配置好的ng模块,来供测试用例里进行调用。具体使用如下:
it('should provide a version', inject(function(mode, version) {
expect(version).toEqual('v1.0.1');
expect(mode).toEqual('app');
其实inject里面就是利用angular.inject方法创建的一个内置的依赖注入实例,然后里面的模块和普通的ng模块的依赖处理是一样的。
Controller部分
Angular模块是todoApp,控制器是TodoController,当按钮被点击时,TodoController的createNote()函数会被调用。下面是app.js的代码部分。
var todoApp = angular.module('todoApp',[]);
todoApp.controller('TodoController',function($scope,notesFactory){
$scope.notes = notesFactory.get();
$scope.createNote = function(){
notesFactory.put($scope.note);
$scope.note='';
$scope.notes = notesFactory.get();
todoApp.factory('notesFactory',function(){
put: function(note){
localStorage.setItem('todo' + (Object.keys(localStorage).length + 1), note);
get: function(){
var notes = [];
var keys = Object.keys(localStorage);
for(var i = 0; i & keys. i++){
notes.push(localStorage.getItem(keys[i]));
在todoController中用了个叫做notesFactory的服务来存储和提取笔记。当createNote()被调用时,会使用这个服务将一条信息存入LocalStorage中,然后清空当前的note。因此,在编写测试模块是,应该保证控制器初始化,scope中有一定数量的笔记,在调用createNote()之后,笔记的数量应该加一。
具体的单元测试如下:
describe('TodoController Test', function() {
beforeEach(module('todoApp')); // 将会在所有的it()之前运行
// 我们在这里不需要真正的factory。因此我们使用一个假的factory。
var mockService = {
notes: ['note1', 'note2'], //仅仅初始化两个项目
get: function() {
return this.
put: function(content) {
this.notes.push(content);
// 现在是真正的东西,测试spec
it('should return notes array with two elements initially and then add one',
inject(function($rootScope, $controller) { //注入依赖项目
var scope = $rootScope.$new();
// 在创建控制器的时候,我们也要注入依赖项目
var ctrl = $controller('TodoController', {$scope: scope, notesFactory:mockService});
// 初始化的技术应该是2
expect(scope.notes.length).toBe(2);
// 输入一个新项目
scope.note = 'test3';
// now run the function that adds a new note (the result of hitting the button in HTML)
// 现在运行这个函数,它将会增加一个新的笔记项目
scope.createNote();
// 期待现在的笔记数目是3
expect(scope.notes.length).toBe(3);
在beforeEach中,每一个测试用例被执行之前,都需要加载模块module("todoApp") 。
由于不需要外部以来,因此我们本地建立一个假的mockService来代替factory,用来模拟noteFactory,其中包含相同的函数,get()和put() 。这个假的factory从数组中加载数据代替localStorage的操作。
在it中,声明了依赖项目$rootScope和$controller,都可以由Angular自动注入,其中$rootScope用来获得根作用域,$controller用作创建新的控制器。
$controller服务需要两个参数。第一个参数是将要创建的控制器的名称。第二个参数是一个代表控制器依赖项目的对象,
$rootScope.$new()方法将会返回一个新的作用域,它用来注入控制器。同时我们传入mockService作为假factory。
之后,初始化会根据notes数组的长度预测笔记的数量,同时在执行了createNote()函数之后,会改变数组的长度,因此可以写出两个测试用例。
Factory部分
factory部分的单元测试代码如下:
describe('notesFactory tests', function() {
// 在所有it()函数之前运行
beforeEach(function() {
// 载入模块
module('todoApp');
// 注入你的factory服务
inject(function(notesFactory) {
factory = notesF
var store = {
todo1: 'test1',
todo2: 'test2',
todo3: 'test3'
spyOn(localStorage, 'getItem').andCallFake(function(key) {
return store[key];
spyOn(localStorage, 'setItem').andCallFake(function(key, value) {
return store[key] = value + '';
spyOn(localStorage, 'clear').andCallFake(function() {
store = {};
spyOn(Object, 'keys').andCallFake(function(value) {
var keys=[];
for(var key in store) {
keys.push(key);
// 检查是否有我们想要的函数
it('should have a get function', function() {
expect(angular.isFunction(factory.get)).toBe(true);
expect(angular.isFunction(factory.put)).toBe(true);
// 检查是否返回3条记录
it('should return three todo notes initially', function() {
var result = factory.get();
expect(result.length).toBe(3);
// 检查是否添加了一条新纪录
it('should return four todo notes after adding one more', function() {
factory.put('Angular is awesome');
var result = factory.get();
expect(result.length).toBe(4);
在TodoController模块中,实际上的factory会调用localStorage来存储和提取笔记的项目,但由于我们单元测试中,不需要依赖外部服务去获取和存储数据,因此我们要对localStorage.getItem()和localStorage.setItem()进行spy操作,也就是利用假函数来代替这两个部分。
spyOn(localStorage,'setItem')andCallFake()是用来用假函数进行监听的。第一个参数指定需要监听的对象,第二个参数指定需要监听的函数,然后andCallfake这个API可以编写自己的函数。因此,测试中完成了对localStorage和Object的改写,使函数可以返回我们自己数组中的值。
在测试用例中,首先检测新封装的factory函数是否包含了get()和put()这两个方法,,然后进行factory.put()操作后断言笔记的数量。
Filter部分
我们添加一个过滤器。truncate的作用是如果传入字符串过长后截取前10位。源码如下:
todoApp.filter('truncate',function(){
return function(input,length){
return (input.length & length ? input.substring(0,length) : input);
所以在单元测试中,可以根据传入字符串的情况断言生成子串的长度。
describe('filter test',function(){
beforeEach(module('todoApp'));
it('should truncate the input to 1o characters',inject(function(truncateFilter){
expect(truncateFilter('abcdefghijkl',10).length).toBe(10);
之前已经对断言进行讨论了,值得注意的一点是我们需要在调用过滤器的时候在名称后面加入Filter,然后正常调用即可。
Directive部分
源码中的指令部分:
todoApp.directive('customColor', function() {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.css({'background-color': attrs.customColor});
由于指令必须编译之后才能生成相关的模板,因此我们要引入$compile服务来完成实际的编译,然后再测试我们想要进行测试的元素。
angular.element()会创建一个jqLite元素,然后我们将其编译到一个新生成的自作用域中,就可以被测试了。具体测试用例如下:
describe('directive tests',function(){
beforeEach(module('todoApp'));
it('should set background to rgb(128, 128, 128)',
inject(function($compile,$rootScope) {
scope = $rootScope.$new();
// 获得一个元素
elem = angular.element("&span custom-color=\"rgb(128, 128, 128)\"&sample&/span&");
// 创建一个新的自作用域
scope = $rootScope.$new();
// 最后编译HTML
$compile(elem)(scope);
// 希望元素的背景色和我们所想的一样
expect(elem.css("background-color")).toEqual('rgb(128, 128, 128)');
开始端到端测试
在端到端测试中,我们需要从用户的角度出发,来进行黑盒测试,因此会涉及到一些DOM操作。将一对组件组合起来然后检查是否如预想的结果一样。
在这个demo中,我们模拟用户输入信息并按下按钮的过程,检测信息能否被添加到localStorage中。
在E2E测试中,需要引入angular-scenario这个文件,并且建立一个html作为运行report的展示,在html中包含带有e2e测试代码的执行js文件,在编写完测试之后,运行该html文件查看结果。具体的e2e代码如下:
describe('my app', function() {
beforeEach(function() {
browser().navigateTo('../../app/notes.html');
var oldCount = -1;
it("entering note and performing click", function() {
element('ul').query(function($el, done) {
oldCount = $el.children().
input('note').enter('test data');
element('button').query(function($el, done) {
$el.click();
it('should add one more element now', function() {
expect(repeater('ul li').count()).toBe(oldCount + 1);
我们在端到端测试过程中,首先导航到我们的主html页面app/notes.html,可以通过browser.navigateTo()来完成,element.query()函数选择了ul元素并记录其中有多少个初始化的项目,存放在oldCount变量中。
然后通过input('note').enter()来键入一个新的笔记,然后模拟一下点击操作来检查是否增加了一个新的笔记(li元素)。然后通过断言可以将新旧的笔记数进行对比。
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具

我要回帖

更多关于 百度前端自动化测试 的文章

 

随机推荐