mocha-casperjs 环境搭建

5 篇文章 0 订阅
1 篇文章 0 订阅

之前一直想尝试前端的自动化测试,一直不知道怎么去入手。众所周知,前端的页面尤其是面向普通用户的页面的话,从用户交互的角度来说,ui的操作占据了绝大部分,ui的这部分的测试(点击,切换等等操作)很难来实现自动化的测试,之前查过一些资料,尝试写过jasmine、karma、selenium之类的工具的demo,当时觉得,一是测试用例不好写,二是很多东西是ui的自动化测试,这种测试版实现起来太麻烦,所以就丢到一边了。这里要吐槽一下自己,前端其实有很多发展的方向,都很不错,很多时候自己都是简单尝试一下,也没有深入的去研究,很多时候可能还是一个兴趣的问题吧。

回到自动化测试上来说,为什么最近我又重新想起了这个东西。我工作有一年多了,基本上就是在开发维护两个项目,一个项目基本上是维护,我来的时候,那个项目已经比较成熟了,另一个项目是我入职后才开始的,所以很多代码都是我写的,但是当时项目做得比较急,而且当时比较水,我们组也没有code review的这个步骤,所以就导致了代码的质量差了点。代码差体现在以下几点:
1.有些业务逻辑处理有问题,这个暂且不表,这个是因为当时没有经验。
2.代码的模块化处理的不好。那时候工作没多久,对整个项目没有一个整体的把握,导致某些该模块化的部分没有模块化,不该模块化的地方模块化了。这一点体现的特别明显,我最开始写的第一个大的功能,js文件达到了1500+行的代码,毫无疑问,这个维护起来就很难了,事实上,现在我再去看那个页面,就会有很多个地方时可以模块化出来的,我现在也在着手拆里面的功能。

3.代码存在大量的冗余。这个有三个原因,一个是某个模块自己本身的代码冗余,这是功力不到的原因,二是某些地方修改之后,为了向后兼容,增加了一些冗余的代码,三是某些需求的修改,比如说原来网站要求支持到IE6,但是后来就变成IE7了,所以之前写过的兼容IE6的代码都是冗余的代码了。

前一段时间,有一个需求,正好会动到我上边提到的文件比较大的那个页,是可以模块化的那一部分,然后我就把那一块摘出来了。摘出来其实是一个比较大的改动,怎么能确保这一个改动不会影响原来的功能呢,只能靠自己的代码的质量来保证,即使是这样子,我改完了之后还是得测一下可能会受影响的功能和页面。又过了一段时间,线上突然间出了一个bug,某个功能不能用了(感谢测试),我一查,之前某个上线的改动影响到这个页了,测试并不清楚这个改动会影响这个页,所以没有人发现。再回到我之前写的代码,早晚我需要优化掉他们,所以我又想起了自动化测试,这样子可以尽量保证优化不影响原有的功能。

简单查了一下,可能业界的前端自动化测试主要是分两个方向,一个是单元的测试,再一个就是ui的测试了。我们的项目单元测试也是耦合了大量的ui操作,当然也可以把我们现在的模块拆成两层,分的更细,让最基础的那一层不依赖于ui,我觉得这个的成本太高,所以就直接研究ui的自动化测试。

先看一下我们要使用到的工具,首先是phantomjs,phantomjs是一个无头浏览器,简单来说就是一个没有实际“显示”的浏览器,虽然你看不到他的显示效果,但是他确实是一个浏览器,很多人用它来写爬虫,我们用它来做最基础的服务。怎么安装就不提了,我是win7,下载下来之后,配置一下环境变量就ok了。

第二个要用到的是casperjs,这个是针对phantomjs的一个封装,包括click、表单填充的功能都封了一层。我初步是这么想的,casperjs的操作是支持链式调用的,通过casperjs.then()来调用,类似于mocha或者jasmine这种断言库,是支持嵌套的,那么这两个组合起来的话,会比较灵活,比如说类似于CMD这样的做法,一个页有一个入口,入口往下是一层一层的测试用例,每一个测试用例代表了一组或者一个操作,单个操作就使用casperjs.then来组合。这是我初步的想法,因为还没有开始真正的写,不知道实际写出来是什么样子的,这个会发后续的文章。casperjs可以通过npm来安装,安装之后也可以配置环境变量来进行全局调用。
第三个要用到的mocha-casperjs,项目地址是https://github.com/nathanboktae/mocha-casperjs,将mocha和casperjs组合起来。也可以通过npm来进行安装。使用的话,windows下面需要调用/bin/mocha-casperjs.bat 而不是/bin/mocha-casperjs,调用后面的这个是调用不到的。可以设置一下环境变量全局调用。调用的方法就是
mocha-casperjs
这个操作会自动寻找并执行调用路径下面的test文件夹(类似于mocha)。这一步我遇到了第一个问题,提示can't open c://progrom,我们来看一下mocha-casperjs的执行文件,/bin/mocha-casperjs.bat 最后一行
casperjs %MOCHA_CASPER_PATH%\cli.js --mocha-casperjs-path=%MOCHA_CASPER_PATH%..%*
可以看到这个入口只是对casperjs调用的一个封装,实际是capsperjs 执行/bin/cli.js ,然后问题来了我安装mocha-casperjs的路径是c://progrom files/...,实际执行的命令就变成了casperjs c://progrom files/xxx/bin/cli.js。请注意progrom files中间的那个空格,我最开始认为是casperjs对路径解析的问题,遇到这种空格错误的解析,后来我发现实际是这种命令行的工具都是这样子的,空格隔开的是参数,所以解析出来的话,c://progrom是路径的参数,所以就会出现can't open c://progrom的错误。解决方法很简单,.bat文件在调用的路径外面套一层引号,把完整路径包起来,这样子就不会出错了。这个问题以后也可能会遇到,所以在这里提一下。
解决了路径问题之后,我们来看一下实际的运行情况,例子类似于mocha-casperjs官方提供的例子,稍微有些许的改动,代码如下:
if (typeof chai === 'undefined') {
  console.log('This example requires chai to be installed adjacent to mocha-casperjs')
  casper.exit(-1)
}

describe('baidu searching', function() {
  before(function() {
    casper.start('http://www.baidu.com/')
  })

  it('should load success', function() {
    casper.then(function() {
      casper.getTitle().should.contain('百度')
      casper.exists('form[action="/s"]').should.be.true
      this.fill('form[action="/s"]', {
        wd: 'casperjs'
      }, true)
    })

    casper.waitForUrl(/wd=casperjs/, function() {
      casper.getTitle().should.match(/casperjs/)
    })
  })
})
调用mocha-casperjs.bat,结果不太符合我们的预期。


三个问题 1.为什么中文会乱码
2.为什么出现了一些乱七八糟的符号,那些带箭头带中括号的是什么鬼???
3.为什么输出的颜色都是黑白的,mocha的输出都带不同的颜色的,像这样

至少,passing要变成绿色的,fail要变成红色的吧。
第一个要解决的是中文乱码的问题,因为命令行的‘当前代码页‘是gbk的,而phantomjs的输出格式应该是utf-8的,所以中文就乱码了。在mocha-casperjs的安装路径下面,/bin/cli.js中,比较靠前的位置(基本上放到最前面就可以了),加上下面这一行。
phantom.outputEncoding="GBK";//设定输出编码
这一行的作用就是设定phantomjs的输出编码格式变为gbk的。

编码的问题解决了之后,第二个就是出现的一些错误的符号,在我试过很多方法之后,尤其是看到了这一篇phantomjs 输出编码错误之后,最后的结论是windows下面的cmd有问题,其实问题也并全是cmd的问题,我试过拿出mocha-casperjs的输出,如果使用node直接console.log的话,实际显示是没问题的,但是放到mocha-casperjs本身就出错了,也许是node调用底层的服务的方式不太一样吧。
言归正传,既然是cmd的问题,那我们就换一个工具,我现在用的是Cmder,可以解决这个问题。我们来看一下现在的效果。
可以看到,原来有特殊字符的地方应该是占位符之类的东西。
最后要解决的是我们要输出带不同的颜色,我参考的是mocha的源码,在这个代码里面搜’passing‘,可以看到mocha在最后输出多少用例成功,多少失败的调用逻辑,
  fmt = color('bright pass', ' ')
    + color('green', ' %d passing')
    + color('light', ' (%s)');

  console.log(fmt,
    stats.passes || 0,
    ms(stats.duration));</span>
很明显,是先装配出了输出的格式,然后直接console输出。我们看一下,color这个函数的实现,
/**
 * Color `str` with the given `type`,
 * allowing colors to be disabled,
 * as well as user-defined color
 * schemes.
 *
 * @param {string} type
 * @param {string} str
 * @return {string}
 * @api private
 */
var color = exports.color = function(type, str) {
  if (!exports.useColors) {
    return String(str);
  }
  return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
};
抛开一些其他的逻辑,实际上就是用‘\u001b[’之类的特殊字符进行的包装,那么这些字符的作用是什么,我们可以看一下这一篇文章,利用正则实现彩色控制台输出,大体上讲的话,就是这些是ansi中的转义字符,语法是\x1b[nm,通过变化n的值来实现不同的颜色。mocha是先定义了一些常用的颜色表,然后在不同的情况下,用不同的颜色包裹起内容,来实现不同颜色的输出。

我们再回到mocha-casperjs,是在哪里实现的输出的格式化呢,在/mocha-casperjs.js中,
  // Mocha needs the formating feature of console.log so copy node's format function and
  // monkey-patch it into place. This code is copied from node's, links copyright applies.
  // https://github.com/joyent/node/blob/master/lib/util.js
  console.format = function (f) {
    ...
  };

  var origError = console.error,
      origLog = console.log
  console.log = function() { origLog.call(console, console.format.apply(console, arguments)) }
这里面提到mocha需要使用console的format输出,因此作者采用了node的util模块的format函数来实现这部分功能,然后在下面重载了console.log函数,那我们这个问题就有解决思路了,重载console.log,拿到原来要输出的内容,然后对某些字符串加上颜色包裹,然后正常输出,应该可以实现我们的功能。/mocha-casperjs增加如下代码:
  console.log = function(){
    var args = colorHandle(arguments);//颜色处理
    origLog.call(console, console.format.apply(console, args));
  }
  var colors = {//对应的颜色列表
    'pass': 90
    , 'fail': 31
    , 'bright pass': 92
    , 'bright fail': 91
    , 'bright yellow': 93
    , 'pending': 36
    , 'suite': 0
    , 'error title': 0
    , 'error message': 31
    , 'error stack': 90
    , 'checkmark': 32
    , 'fast': 90
    , 'medium': 33
    , 'slow': 31
    , 'green': 32
    , 'light': 90
    , 'diff gutter': 90
    , 'diff added': 42
    , 'diff removed': 41
  };
  var colorsMap = {'passing':'green','failing':'fail'};//不同的状态对应的color值
  var colorHandle = function(arguments){//对不同的状态增加不同的显示颜色
    var item, args = Array.prototype.slice.call(arguments);
    for(var i=0, length = args.length; i<length; i++){
      item = args[i];
      if((typeof item).toUpperCase() == 'STRING'){//只针对字符串进行处理
        for(var key in colorsMap){
          if(item.indexOf(key)>=0){
            args[i] = colorHandle_(colorsMap[key], args[i]);//增加颜色
          }
        }
      }
    }
    return args;
  };
  var colorHandle_ = function(type, str){
    return '\u001b[' + colors[type] + 'm' + str + '\u001b[0m';
  };
这里采用就是针对含有关键字的字符串做包裹,实现的比较糙,但是这个思路走下去的话可以对输出做更多个性化的定制,我们来看一下最后的效果。

总结:
经过一番折腾,总算搭建好了mocha-casperjs的基本环境,之后的自动化测试的开发还没有开始,想法也不太成熟,但我还是会试一下,最后的结果之后会另外写文章来写,这个暂且不表。回到这次环境搭建的过程,其实折腾的时间挺长的(虽然看起来东西很简单),最开始的时候,想要利用node的debug模块来控制输出,但是caspejs的require和node的require是不一样的,casperjs的require实际是casperjs的模块,当然你可以直接用绝对地址引用node的模块,但是有的好使有的不好使,很不幸debug不行。后来我还脑洞打开,用browserify封装了一个debug的版本,后来证实browserify的封装会把一些api直接装换成浏览器的api,而且浏览器下的格式输出跟命令行下面的格式输出不兼容,然后这个思路就被放弃了(因为这个还大概了解了一下browserify的原理,也算一个收获吧,并不是直接封装node的模块而是转成了浏览器下的可以识别的代码,大概猜测是这样子的)。再到后来,就参考了mocha的源码解决了这个问题。其实解决这个问题的过程挺痛苦的,关键在于自己的思路不够清晰,从一开始的四处乱撞,找mocha-casperjs的配置项,到后面一步一步的接近正确的答案,关键还在于思路要清晰,每一次的尝试要有理有据,要找对点,自己是一个写程序的,要从代码上解决问题,而不是靠运气。

好啦,这是我的第三篇博客,之前说要一直更的,但是懒啊。上次backbone写完之后,还尝试过react.js,觉得挺好用的,也没有记录一下,看以后有没有机会补上,不过我看悬,哈哈,继续努力啦。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值