現代化測試開發技巧

劉艾霖 (Alin)

2017 Testing Day

@alincode

  • 創科資訊
  • 技術顧問 /  企業內訓講師
  • 講者
    • Modern Web 2016
    • JSDC.tw 2016
  • 全端開發者 & 測試開發

1. 選擇框架

2. Tips

3. 快速入門 & demo

選擇前端測試框架

為什麼我們要採用

前端測試框架?

begin...

Selenium IDE

const {Builder, By, until} = require('webdriver');

var driver = new Builder()
    .forBrowser('firefox')
    .build();

driver.get('http://www.google.com/ncr')
    .then(_ => driver.findElement(By.name('q')).sendKeys('webdriver'))
    .then(_ => driver.findElement(By.name('btnG')).click())
    .then(_ => driver.wait(until.titleIs('webdriver - Google Search'), 1000))
    .then(_ => driver.quit());

Webdriver

但這些都還不夠...

你說啥...

這樣還不夠...

產出測試報表

與持續整合流程結合

儘可能地減輕寫測試程式的負擔

友善的測試結果訊息

.......

.....

...

支線目標

產出測試報報表

與持續整合流程結合

儘可能地減輕寫測試程式的負擔

Webdriver.IO

driver.get('http://www.google.com');
driver.findElement(webdriver.By.id('q')).sendKeys('webdriver');
driver.findElement(webdriver.By.id('btnG')).click();
client.url('http://google.com')
      .setValue('#q', 'webdriver')
      .click('#btnG')

Webdriver

注意力放在測試邏輯

而不是實作細節

友善的測試結果訊息

選用測試框架

分辨

測試框架的用途

特性

describe('Protractor Demo App', function() {
  it('should add one and two', function() {
    browser.get('http://juliemr.github.io/protractor-demo/');
    element(by.model('first')).sendKeys(1);
    element(by.model('second')).sendKeys(2);

    element(by.id('gobutton')).click();

    expect(element(by.binding('latest')).getText()).
        toEqual('5'); // This is wrong!
  });
});
const assert = require('assert');

describe('angularjs', () => {
  it('should add one and two ', () => {
    browser.url('http://juliemr.github.io/protractor-demo/');
    $('[ng-model=first]').setValue(1);
    $('[ng-model=second]').setValue(2);
    $('#gobutton').click();
    browser.pause(7000);
    assert.equal($('.ng-binding').getText(), 3);
  });
});

WebdriverIO

framework agnostic

整合度

是不是可以一魚多吃

擴充度

命令

報表

格式

外掛

服務

實務上的 Tips

用 ReactJS, AngularJS 寫的網站

可不可以測?

Sure

常常遇到拋出 element

不存在的 error?

多用 waitFor

少用 browser.pause(3000)

測試程式

越來越難維護

Pattern 無所不在

所以...

class Page {
  constructor() {
    this.title = 'My Page';
  }
  open(path) {
    browser.url('/' + path);
  }
}
module.exports = new Page();
var Page = require('./page')

class LoginPage extends Page {
    get username()  { return browser.element('#username'); }
    get password()  { return browser.element('#password'); }
    get form()      { return browser.element('#login'); }
    get flash()     { return browser.element('#flash'); }
    open()          { super.open('login'); }
    submit()        { this.form.submitForm(); }
}

module.exports = new LoginPage();

page.js

loginPage.js

Page Object Pattern

ES6

var expect = require('chai').expect;
var LoginPage = require('../pageobjects/login.page');
describe('login form', function () {
    it('登入失敗流程', function () {
        LoginPage.open();
        LoginPage.username.setValue('alincodeeeeee');
        LoginPage.password.setValue('hello');
        LoginPage.submit();
        expect(LoginPage.flash.getText()).to.contain('這個帳號不存在');
    });
    it('登入成功流程', function () {
        LoginPage.open();
        LoginPage.username.setValue('alincode');
        LoginPage.password.setValue('hello');
        LoginPage.submit();
        expect(LoginPage.flash.getText()).to.contain('你登入成功');
    });
});
LoginPage.open();
LoginPage.username.setValue('alincode');
LoginPage.password.setValue('hello');
LoginPage.submit();

測試環境好難架設

Selenium Server

Browser Version

Browser Driver

Selenium Hub & Node

Cloud Browser

30 美金

能解決的都不是問題

可是瑞凡...

我就是沒有錢

docker-selenium

Selenium node

Selenium Grid Hub

Selenium standalone

VNC server

可是... 可是... 可是...

測試好難寫啊...

REPL

可是... 可是... 可是...

寫測試好花時間啊...

你聽過安麗嗎

你聽過 hot reload 嗎

要怎麼與 CI / CD

流程整合

快速入門前端測試

Live Demo

cloud service

總結

寫測試其實沒這麼難

現在已經 2017 了

如果驗收後

不補個前端測試

你就會發現...

某天你的客戶問你...

或許當時就是時空背景下

定義詭異的流程

他實際上並不是一個 bug

是一個需求啊...

因為時間有限...

還想知道更多...

現代化測試開發技巧

By alincode

現代化測試開發技巧

  • 2,611