codeceptjs学习笔记 - 安装和基本知识

本文章基于codeceptjs@1.0.1

codeceptjs介绍

codeceptjsCodeception测试框架下的一个项目,是运行在nodejs的UI测试框架, 能使场景驱动的验收测试简单化。

"Modern Era Acceptance Testing Framework for NodeJS"是codeceptjs官网最显著的标语,那作为一个UI测试框架,究竟有哪些特点:

  • 从用户角度编写。codeceptjs提供的API具有declarative testing的特点,从用户行为的角度抽象出了许多与浏览器的交互动作,测试代码非常易读易懂。codeceptjs提供的API由于其易读性也可以当成DSL来使用,这些DSL隐藏了后端webdriver服务的复杂性,可以让使用者更加专注到测试场景的编写中
  • 所有的交互动作来自于对象I。对象I的方法都被描述为用户访问网站可能产生的行为,易读易写易维护,对非技术人员也很友好
  • 对多个后端API兼容。codeceptjs支持多个webdriver实现 i.e. webdriverio, protractor and phantomjs, 我们可以很简单在他们之间切换。这些不同的webdriver实现在codeceptjs里面叫做Helper,正是下面这些Helper给对象I提供了actions
  • 同步。我们不用关心js中的异步问题 i.e. promises & callback。测试场景是线性的
  • 基于Mocha测试框架
  • 可以编写出易读易懂的场景驱动的验收测试。可以写成BDD style
  • Smart locator。Smart locators: use names, labels, matching text, CSS or XPath to locate elements
  • 互动式debug shell。可以在测试执行时随时暂停然后尝试codeceptjs提供地不同的API
  • 提供了方便的命令行工具帮助创建测试。可以通过命令一步创建tests, pageobjects, stepobjects
  • 支持web和mobile端的测试

说了这么多特点,它长什么样子呢?一个简单的demo如下:

Feature('CodeceptJS demo');

Scenario('check Welcome page on site', (I) => {
  I.amOnPage('/');
  I.see('Welcome');
});

是不是可以基本当plain text来读?:)

codeceptjs安装

环境检查

在安装codeceptjs之前,你要确保你的node版本是大于6.11的

$ node -v              
v8.3.0
安装codeceptjs

使用npm全局安装codeceptjs,这样的话我们就可以在shell里面直接使用codeceptjs命令

[sudo] npm install -g codeceptjs

本地安装, 这样的话我们可以执行./node_modules/.bin/codeceptjs

npm install --save-dev codeceptjs

安装browser driver

全局安装webdriverio
[sudo] npm install -g webdriverio

本地安装webdriverio
npm install webdriverio --save-dev

全局安装protractor
[sudo] npm install -g protractor

本地安装protractor
npm install protractor --save-dev

全局安装nightmare
[sudo] npm install -g nightmare nightmare-upload

本地安装nightmare
npm install nightmare nightmare-upload --save-dev

全局安装codeceptjs+webdriverio
[sudo] npm install -g codeceptjs-webdriverio

本地安装codeceptjs+webdriverio
[sudo] npm install codeceptjs-webdriverio --save-dev

全局安装codeceptjs+nightmare
[sudo] npm install -g codeceptjs-nightmare

本地安装codeceptjs+nightmare
[sudo] npm install codeceptjs-nightmare --save-dev

全局安装codeceptjs+protractor
[sudo] npm install -g codeceptjs-protractor

本地安装codeceptjs+protractor
[sudo] npm install codeceptjs-protractor --save-dev

安装完之后你可以通过codeceptjs命令查看codeceptjs的版本和常用命令参数介绍

➜  codeceptjs-demo git:(master) ✗ codeceptjs
CodeceptJS v1.0.1

  Usage:  [options] [command]


  Options:

    -h, --help  output usage information


  Commands:

    init [path]                          Creates dummy config in current dir or [path]
    shell|sh [options] [path]            Interactive shell
    list|l [path]                        List all actions for I.
    def [path]                           List all actions for I.
    generate:test|gt [path]              Generates an empty test
    generate:pageobject|gpo [path]       Generates an empty page object
    generate:object|go [options] [path]  Generates an empty support object (page/step/fragment)
    generate:helper|gh [path]            Generates a new helper
    run [options] [test]                 Executes tests
    run-multiple [options] [suites...]   Executes tests multiple

其中参数list可以列出对象I所有的动作,也就是我们可以利用的浏览器交互API

➜  codeceptjs-demo git:(master) ✗ codeceptjs list
List of test actions: --
 WebDriverIO I.defineTimeout(timeouts)
 WebDriverIO I.amOnPage(amOnPage)
 WebDriverIO I.click(click)
 WebDriverIO I.doubleClick(doubleClick)
 WebDriverIO I.rightClick(rightClick)
 ..........
安装selenium-standalone

因为这些helper i.e. webdriverio, protractor都是需要selenium作为后端与browser通信的服务,所以我们也需要安装selenium。

下面的命令会安装selenium standalone server以及相应的browser driver

npm install selenium-standalone@latest -g
selenium-standalone install
selenium-standalone start

详细的selenium-standalone资料请参考这里

codeceptjs基础知识

命令行使用

codeceptjs init可以用在当我们需要初始化一个测试项目的时候。这个命令会创建和配置一些文件来搭建我们的测试环境。
➜  codeceptjs-init: codeceptjs init

  Welcome to CodeceptJS initialization tool
  It will prepare and configure a test environment for you

Installing to /Users/diyu/workspace/codeceptjs_demo/codeceptjs-init
? Where are your tests located? ./*_test.js
? What helpers do you want to use? WebDriverIO
? Where should logs, screenshots, and reports to be stored? ./output
? Would you like to extend I object with custom steps? Yes
? Do you want to choose localization for tests? English (no localization)
? Where would you like to place custom steps? ./steps_file.js
Configure helpers...
? [WebDriverIO] Base url of site to be tested http://localhost
? [WebDriverIO] Browser in which testing will be performed chrome
Steps file created at /Users/diyu/workspace/codeceptjs_demo/codeceptjs-init/steps_file.js
Config created at /Users/diyu/workspace/codeceptjs_demo/codeceptjs-init/codecept.json
Directory for temporary output files created at `_output`
Almost done! Create your first test by executing `codeceptjs gt` (generate test) command
➜  codeceptjs-init: ll
total 16
-rw-r--r--  1 diyu  staff   291B  8 27 22:39 codecept.json
drwxr-xr-x  2 diyu  staff    68B  8 27 22:39 output
-rw-r--r--  1 diyu  staff   281B  8 27 22:39 steps_file.js

如上所示,一些测试文件、配置文件和输出目录都创建好了。具体到这些文件是干嘛的,里面内容是什么,之后的学习笔记后提到。

codeceptjs gt会创建测试文件
➜  codeceptjs-init: codeceptjs gt
Creating a new test...
----------------------
? Filename of a test first
? Feature which is being tested first demo
Test for first was created in /Users/diyu/workspace/codeceptjs_demo/codeceptjs-init/first_test.js
➜  codeceptjs-init: ll
total 24
-rw-r--r--  1 diyu  staff   291B  8 27 22:39 codecept.json
-rw-r--r--  1 diyu  staff    66B  8 27 23:50 first_test.js
drwxr-xr-x  2 diyu  staff    68B  8 27 22:39 output
-rw-r--r--  1 diyu  staff   281B  8 27 22:39 steps_file.js
➜  codeceptjs-init: cat first_test.js

Feature('first demo');

Scenario('test something', (I) => {

});

first_test.js 就是被创建的测试文件

codeceptjs run 会运行测试。加上参数--steps会输出详细的执行过程
➜  codeceptjs-init: codeceptjs run --steps
CodeceptJS v1.0.1
Using test root "/Users/diyu/workspace/codeceptjs_demo/codeceptjs-init"

first demo --
 test something
 ✓ OK in 1ms

  OK  | 1 passed   // 2s
codeceptjs gpo会创建一个page object file。这个命令可以快速简单的帮助你实现page object设计模式
➜  codeceptjs-init codeceptjs gpo
Creating a new page object
--------------------------
? Name of a page object landingPage
? Where should it be stored ./pages/landingPage.js
Updating configuration file...
Page object for landingPage was created in /Users/diyu/workspace/codeceptjs_demo/codeceptjs-init/pages/landingPage.js
Use landingPagePage as parameter in test scenarios to access it
➜  codeceptjs-init ll
total 24
-rw-r--r--  1 diyu  staff   375B  8 29 21:30 codecept.json
-rw-r--r--  1 diyu  staff    66B  8 27 23:50 first_test.js
drwxr-xr-x  2 diyu  staff    68B  8 27 22:39 output
drwxr-xr-x  3 diyu  staff   102B  8 29 21:30 pages
-rw-r--r--  1 diyu  staff   281B  8 27 22:39 steps_file.js

landingPage.js被创建在pages目录下面,这个文件里面会有landingPage的元素定位和基本操作。一个简单的demo如下

'use strict';

let I;

module.exports = {

  _init() {
    I = actor();
  },

  fields: {
    email: '#user_basic_email',
    password: '#user_basic_password'
  },
  submitButton: {css: '#new_user_basic input[type=submit]'},

  sendForm(email, password) {
    I.fillField(this.fields.email, email);
    I.fillField(this.fields.password, password);
    I.click(this.submitButton);
  }
}

通过参数传递的方式,我们可以在测试文件里面注入页面元素和操作

Feature('CodeceptJS Demonstration');

Before((I) => { // or Background
  I.amOnPage('http://simple-form-bootstrap.plataformatec.com.br/documentation');
});

Scenario('test some forms', (I, docsPage) => {
  docsPage.sendForm('hello@world.com','123456');
  I.see('User is valid');
  I.dontSeeInCurrentUrl('/documentation');
});

这样的话,最简单的page object就可以用了

Actions and Assertions

下面通过一个简单的demo来看下codeceptjs测试文件长什么样子

Feature('CodeceptJS Demonstration');

Scenario('test some forms', (I) => {
  I.amOnPage('http://simple-form-bootstrap.plataformatec.com.br/documentation');
  I.fillField('Email', 'hello@world.com');
  I.fillField('Password', '123456');
  I.checkOption('Active');
  I.checkOption('Male');
  I.click('Create User');
  I.see('User is valid');
  I.dontSeeInCurrentUrl('/documentation');
});

可以看出

  • 所有的页面操作都由对象I调用执行,而I的方法都来自于Helper
  • see(),dontSee()方法是用来做验证的。可以在页面上找到指定元素进行验证.如果第二个参数提供,可以缩小元素查找范围。I.see('User is valid', '.alert-success');
  • Feature和Scenario来源于mocha
  • fillField(), checkOption()和click()这些方法工作原理类似,都是通过name, css和xpath找到元素并与之交互

Grabber

当我们需要从页面中抓取元素然后用到后续测试的时候,我们可以使用带grab前缀的方法。它的用法如下

var assert = require('assert');

Feature('CodeceptJS Demonstration');

Scenario('test page title', function*(I) {
  I.amOnPage('http://simple-form-bootstrap.plataformatec.com.br/documentation');
  var title = yield I.grabTitle();
  assert.equal(title, 'Example application with SimpleForm and Twitter Bootstrap');
});

grad()要被使用在generator里面,所以带有yield关键字

debug

codeceptjs可以通过两种方式进行测试代码开发中的调试

  • 在测试文件中使用pause()方法
➜  codeceptjs-init codeceptjs run --steps
CodeceptJS v1.0.1
Using test root "/Users/diyu/workspace/codeceptjs_demo/codeceptjs-init"

CodeceptJS Demonstration --
 test some forms
 • I am on page "http://simple-form-bootstrap.plataformatec.com.br/documentation"
 • I fill field "Email", "hello@world.com"
 • I fill field "Password", "123456"
 • I check option "Active"
 Interative debug session started
 Use JavaScript syntax to try steps in action
 Press ENTER to continue
 I.
Exiting interactive shell....
 • I check option "Male"
 • I click "Create User"
 • I see "User is valid"
 • I dont see in current url "/documentation"
 ✓ OK in 12581ms

注意到中间突然出现了交互式的debug session,这就是pause()的作用

  • 下面这种codeceptjs shell来进行调试
➜  codeceptjs-init codeceptjs shell
String interactive shell for current suite...
 Interative debug session started
 Use JavaScript syntax to try steps in action
 Press ENTER to continue
 I.amOnPage('www.hupu.com')
 I.

通过这个互动的debug session,我们可以一步步的输入不同的action来观察浏览器的行为

Before()/After()

codeceptjs也提供了测试框架必不可少的用作测试准备setup和清理teardown的方法。Before()和Background()可以用于抽取公共方法或做测试准备工作,After()可以用于测试收尾清理工作。

Before()和Background()会在所有Scenario()之前执行一样,After()会在所有Scenario()之后执行。

下面的测试代码片段中Before()会在所有Scenario()方法之前执行。Before()也可以换成Background()。

Feature('CodeceptJS Demonstration');

Before((I) => { // or Background
  I.amOnPage('http://simple-form-bootstrap.plataformatec.com.br/documentation');
});

After((I) => {
  I.clearCookie();
});

Scenario('test some forms', (I) => {
  I.click('Create User');
  I.see('User is valid');
  I.dontSeeInCurrentUrl('/documentation');
});

Scenario('test title', (I) => {
  I.seeInTitle('Example application');
});

BeforeSuite()/AfterSuite()

当你需要在所有的测试Scenario()之前进行复杂的setup和teardown,BeforeSuite()/AfterSuite()会是好的选择。BeforeSuite()会在所有的Scenario(), Before()之前调用运行;同理,AfterSuite()会在所有的Scenario(), Before()之后调用运行;这两个方法有且只运行一次。

由于BeforeSuite()/AfterSuite()有可能是在浏览器打开之前运行,所有BeforeSuite()/AfterSuite()只能访问到I对象。BeforeSuite()/AfterSuite()只会在声明的文件中生效,所以不同的文件就可以有不同的BeforeSuite()/AfterSuite()了。

BeforeSuite((I) => {
  I.syncDown('testfolder');
});

AfterSuite((I) => {
  I.syncUp('testfolder');
  I.clearDir('testfolder');
});

within('section', ()=>{})

使用within('section', ()=>{})可以让一系列I对象的方法在页面某个特定区域执行.这样可以锁定具体的执行范围。

Feature('within demo')

Scenario('login github', (I)=>{
    I.amOnPage('https://github.com');
    within('.form-signup-home', () => {
      I.fillField('user[login]', 'User');
      I.fillField('user[email]', 'user@user.com');
      I.fillField('user[password]', 'user@user.com');
      I.click('button');
    });
    I.see('There were problems creating your account.');
});

Comments I.say()

给测试场景添加注释,可以使用I.say()

Feature('within demo')

Scenario('login github', (I)=>{
    I.amOnPage('http://www.baidu.com');
    I.say('Above is the link for baidu search engine');
});

Skip test

使用xScenario()可以跳过测试的执行。

只执行一个测试场景

使用Scenario.only()可以只运行该测试。

Reporter

之前提到codeceptjs是基于mocha的,所有mocha的--reporter也对codeceptjs有效。我们可以用下面命令指定report的格式

codeceptjs run --steps --reporter spec (这是default的report格式)

spec可以替换为dot, nyan, tap等。详细内容请参考这里

XML report

使用mocha-junit-reporter可以产生一个xml报告,这对jenkins非常友好。

安装 npm i mocha-junit-reporter

把报告放到output目录下

"mocha": {
  "reporterOptions": {
      "mochaFile": "output/result.xml"
  }
},

使用codeceptjs run --reporter mocha-junit-reporter 来执行测试产生xml报告,最终的报告会被放在 output/result.xml。

HTML report

因为codeceptjs是基于mocha的,所以我们可以使用mochawesome来产生好看的HTML报告。

安装 npm i mochawesome

把报告放到output目录下

"mocha": {
  "reporterOptions": {
      "reportDir": "output"
  }
},

使用codeceptjs run --reporter mochawesome 来执行测试产生html报告,最终的报告会被放在 output/mochawesome.html。

对于失败的测试,我们需要有截图,我们可以使用下面的配置来实现

"helpers": {
    "Mochawesome": {
        "uniqueScreenshotNames": "true"
    }
  },

Test Options

Feature()和Scenario()的第二个参数可以是一对键值对,这个参数的作用是为测试场景提供一些选项比如timeout和retry

Feature('My feature', {key: val});

Scenario('My scenario', {key: val}, (I) => {});
Timeout

默认状态下,测试场景是没有timeout的,我们可以通过传递下面的键值对来设置feature级别或是scenario级别的timeout

// set timeout to 5s
Feature('Stop me', {timeout: 5000});

// set timeout to 1s
Scenario("Stop me faster", {timeout: 1000}, (I) => {});

// disable timeout for this scenario
Scenario("Don't stop me", {timeout: 0}, (I) => {});
Retries

UI测试是不稳定的,有些时候我们需要rerun来让相应的测试场景通过。我们可以通过在Feature()和Scenario()中传递retries键值对来实现。


//所有scenario失败后都会retry3次
Feature('Complex JS Stuff', {retries: 3})

//这个scenario失败后只会retry1次
Scenario('Not that complex', {retries: 1}, (I) => {
  // test goes here
});
//这个scenario失败后会retry3次
Scenario('Really complex', (I) => {
  // test goes here
});
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容