测试

单元测试

它可以是一个函数、一个模块、一个包或者一个类,甚至是一个对象(比如 JavaScript 和 Scala 语言)。在 JavaScript 中,通常是以类或者模块作为一个单元。以单元进行测试很重要的一点是其测试是独立的,应该是测试的基础

对于相关功能的模块

  • 两个模块进行测试
  • 使用mock,模拟操作,或者进行参数传递

细节

  • 尽量避免不要几个单元互相引用

分类

  • TDD 测试驱动开发
    通过测试推动整个开发的进行,同时将需求分析,设计,质量控制量化的过程

  • BDD 行为驱动开发
    并不仅仅是为了测试,QA工程师,注重业务需求,降低了客户、用户、项目管理者与开发者之间来回翻译的成本

使用工具  Mocha + Karma

  • 运行在node环境
  • 单元测试不需要外部以来,使用$rootScope创造新的作用域,并创建新的控制器(创建假的服务并注入)
  • 使用spyOn(object, “fmethod”).andCallFake()来转化成假的函数,即知名监听的函数替换成自己写的函数

示例

端到端测试

与生产环境有一样的配置,应用当中的功能都会被测试到

缺点

  • 比较缓慢,而且和用户界面紧密耦合

模块功能

  • 浏览器的执行是异步的因此有时候需要进行重试,使用promise-retry模块
  • webdrive的所有事件都是异步的
  • 可以运用BY模块进行定位元素By.css,By.javascript
1
const operatorEquals = await driver.findElement(By.css('.operator-equals'))
  • 相当与模拟用户的操作,黑盒测试

使用技术

  • mocha
  • dom.js,围绕发生交互的用户界面元素
  • CasperJS只能与无界面浏览器使用,测试运行的效率快,但无法排查解决浏览器兼容性问题
  • Protractor,这是angular官方使用的E2E测试框架,组织方式可以使用Mocha

细节

  • 实际上是模拟了用户的所有可能的操作,保证输出的结果都是正确的
  • 建立在单元测试的基础,需要的数量并不会很多,模块之前的测试,允许不稳定测试

实现

jasmine + Protractor

  • Jasmine

Jasmine就是一个行动驱动开发模式的JS的单元测试工具。

  • describe
    describe 是 Jasmine 的全局函数,作为一个 Test Suite 的开始,它通常有 2 个参数:字符串和方法。字符串作为特定 Suite 的名字和标题。
  • specs
    调用it来定义,包含expectations来测试
  • Matchers
    判断expectation的真假,然后判定spec是否通过

实例:

1
2
3
4
5
6
7
8
describe("The 'toBe' matcher compares with ===", function() {
it("and has a positive case ", function() {
expect(true).toBe(true);
});
it("and can have a negative case", function() {
expect(false).not.toBe(true);
});
});

  • Setup and Teardown
    在每一个spec的运行之前和运行之后可以定义一些变量的初始化或者重置之类的工作,提高代码的复用程度和相关性

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
describe("An example of setup and teardown)", function() {
var gVar;

beforeEach(function() {
gVar = 3.6;
gVar += 1;
});

afterEach(function() {
gVar = 0;
});

it("after setup, gVar has new value.", function() {
expect(gVar).toEqual(4.6);
});

it("A spec contains 2 expectations.", function() {
gVar = 0;
expect(gVar).toEqual(0);
expect(true).toEqual(true);
});
});

  • describe可以嵌套,注意嵌套之后的每个it的执行需要按照树结构遍历,顺序执行相应的beforeEach和afterEach

Protrator

官方文档

是基于angular应用的端对端测试框架,在真实的浏览器当中运行测试脚本,同时模拟用户操作与应用进行交互

  • 原理

    • selenium是是一个浏览器自动化的框架,包含了服务,api和相应的浏览器驱动
    • Potractor对WebDriverJS进行封装,使用Jasmine测试框架,用javascript绑定相应的api
    • 将test脚本发送到selenium服务器,WebDriverJS是对JSON wire protocol 的包装,然后与浏览器端进行通信,通过设备驱动来让浏览器执行用户行为

    • 以看到脚本的运行需要三个进程之间的通信,以各自之间的协议进行通信
    • 注意每一步的操作都是异步,因此在js中要使用promise
  • 安装
1
2
3
npm install -g protractor
webdriver-manager update
webdriver-manager start

webdriver-manager 可以讲测试的相关信息输出在本地的服务器 http://localhost:4444/wd/hub.

  • 基本用法

    文件结构分成主要测试文件 spec,js 和配置文件 conf.js

    1. Jasmine格式,用describe,it,expectation
    2. browser.get 浏览器跳转
    3. element(by.model/id.binding)定位元素
    4. slement.all 绑定 repeat元素
    5. conf设置,多线程,多浏览器
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      	exports.config = {
      framework: 'jasmine',
      seleniumAddress: 'http://localhost:4444/wd/hub',
      specs: ['spec.js'],
      multiCapabilities: [{
      browserName: 'firefox'
      }, {
      browserName: 'chrome'
      }]
      }

spec示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
describe('Protractor Demo App', function() {
var firstNumber = element(by.model('first'));
var secondNumber = element(by.model('second'));
var goButton = element(by.id('gobutton'));
var latestResult = element(by.binding('latest'));
var history = element.all(by.repeater('result in memory'));

function add(a, b) {
firstNumber.sendKeys(a);
secondNumber.sendKeys(b);
goButton.click();
}

beforeEach(function() {
browser.get('http://juliemr.github.io/protractor-demo/');
});

it('should have a history', function() {
add(1, 2);
add(3, 4);

expect(history.count()).toEqual(2);

add(5, 6);

expect(history.count()).toEqual(0); // This is wrong!
});
});