Recommended
PDF
自動化を支えるCI/CDツールの私の選択 ~何をするためにCI/CDツールを選ぶか~
PDF
Getting Started with Testing using PHPUnit
PDF
PDF
PDF
PDF
PPT
PDF
JobStreamerではじめるJavaBatchのクラウド分散実行
PDF
Introduction to Continuous Test Runner MakeGood
KEY
PDF
Jjug 20140430 gradle_basic
PDF
テスティングフレームワークに入門してみた - Swift編
PDF
PPT
How to manage Cakephp @CakePHP_Fukuoka_2
PPT
PDF
PPT
PDF
Spring in-summer-gradle-hands on-withanswers
PDF
PPT
PDF
PDF
PPTX
PDF
PDF
griffon plugin を 実際に作ってみよう #jggug
PDF
あなたの安心を高速に守る Container-based CI
PPT
PDF
大規模な負荷でもドキドキしない為のJava EE
PDF
JS開発におけるTDDと自動テストツール利用の勘所
PDF
人生がときめくAPIテスト自動化 with Karate
More Related Content
PDF
自動化を支えるCI/CDツールの私の選択 ~何をするためにCI/CDツールを選ぶか~
PDF
Getting Started with Testing using PHPUnit
PDF
PDF
PDF
PDF
PPT
PDF
JobStreamerではじめるJavaBatchのクラウド分散実行
What's hot
PDF
Introduction to Continuous Test Runner MakeGood
KEY
PDF
Jjug 20140430 gradle_basic
PDF
テスティングフレームワークに入門してみた - Swift編
PDF
PPT
How to manage Cakephp @CakePHP_Fukuoka_2
PPT
PDF
PPT
PDF
Spring in-summer-gradle-hands on-withanswers
PDF
PPT
PDF
PDF
PPTX
PDF
PDF
griffon plugin を 実際に作ってみよう #jggug
PDF
あなたの安心を高速に守る Container-based CI
PPT
PDF
大規模な負荷でもドキドキしない為のJava EE
Similar to ゼロから始めたE2Eテスト
PDF
JS開発におけるTDDと自動テストツール利用の勘所
PDF
人生がときめくAPIテスト自動化 with Karate
KEY
PDF
PDF
PDF
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
PDF
SeleniumE2Eテストフレームワークを使用したテスト自動化事例 #Seleniumjp
PDF
G*workshop 2011/11/22 Geb+Betamax
PPTX
PDF
JavaScriptでWebDriverのテストコードを書きましょ
PDF
PDF
Karateによる UI Test Automation 革命
PDF
【17-B-6】RIAの性能テストとアプリケーション品質向上のための管理手法
PDF
受託開発でテストファーストしたらXXXを早期発見できてハイアジリティになったはなし
PDF
Rails A/B testing by split gem
PDF
PDF
PPTX
PDF
PPTX
Webアプリのシナリオテスト自動化を運用に乗せるまでの10のステップ
ゼロから始めたE2Eテスト 1. 2. 3. 4. E2Eテストとは
● End to End テストの略
● システム全体が正しく動作することを確認する
○ Webアプリケーションの場合、ユーザーが行うようにブラウザを操作して結果が期待通りか確認
● 主な特徴
○ コスト高め
○ 実行時間長め
○ 不安定になりやすい
5. 6. 7. 8. 9. 10. 11. 12. (余談)アプリのソースはjQueryベタ書き養殖もの
$(function() {
var fish = [];
var selectedItems = [];
$.ajax('fish.json').done(function(response) {
fish = response.fish;
var $fishesList = $('#fish-list');
$.each(fish, function(i, r) {
$fishesList.append(
$('<tr />')
.append($('<td />').append($('<input type="checkbox" class="select-row" />').data(r)))
.append($('<td />').text(r.name))
);
});
});
});
省略
https://github.com/ushiboy/niigata.js-v2/blob/master/docs/app.js
13. 14. 15. 16. 17. 18. サーバの起動と終了
$ docker-compose up -d
Creating network "case1_default" with the default driver
Creating web ... done
$ docker-compose down
Stopping web ... done
Removing web ... done
Removing network case1_default
19. 20. 21. テストコードの基本構成
const assert = require('power-assert');
const chrome = require('selenium-webdriver/chrome');
const {Builder, By, Key, until} = require('selenium-webdriver');
describe('FishList', function() {
this.timeout(20000);
let driver;
beforeEach(() => {
driver = new Builder()
.forBrowser('chrome')
.setChromeOptions(new chrome.Options().headless())
.build();
});
afterEach(() => {
return driver.quit();
});
it('テストケース', async () => {
// テスト内容
});
});
22. テストケースのコード例
it('一覧が動的に読み込まれること ', async () => {
await driver.get('http://localhost:8080');
let rows;
await driver.wait(async () => {
rows = await driver.findElement(By.id('fish-list')).findElements(By.tagName('tr'));
return rows.length !== 0;
}, 5000);
assert(rows.length === 3);
const cols1 = await rows[0].findElements(By.tagName('td'));
assert(await cols1[1].getText() === 'まぐろ');
const cols2 = await rows[1].findElements(By.tagName('td'));
assert(await cols2[1].getText() === 'はまち');
const cols3 = await rows[2].findElements(By.tagName('td'));
assert(await cols3[1].getText() === 'かつお');
});
23. Single Page Applicationなどでのコツ
● 動的に描画を扱うページの場合
○ ページロード後にすべての描画が完了していない
○ 対象の描画完了を待つ必要がある
■ 要素の変化
■ タイマー
● おすすめは要素の変化を利用する
○ タイマーだと十分な余裕を持った間隔がテスト実行の長さに繋がる
○ 一覧であれば行数の変化とか
○ ローディングマスクが消えたタイミングとか
24. 今回のは行数の変化を監視して待つ例
it('一覧が動的に読み込まれること ', async () => {
await driver.get('http://localhost:8080');
let rows;
await driver.wait(async () => {
rows = await driver.findElement(By.id('fish-list')).findElements(By.tagName('tr'));
return rows.length !== 0;
}, 5000);
assert(rows.length === 3);
const cols1 = await rows[0].findElements(By.tagName('td'));
assert(await cols1[1].getText() === 'まぐろ');
const cols2 = await rows[1].findElements(By.tagName('td'));
assert(await cols2[1].getText() === 'はまち');
const cols3 = await rows[2].findElements(By.tagName('td'));
assert(await cols3[1].getText() === 'かつお');
});
25. (余談)async/await使わないとこうなる
it('一覧が動的に読み込まれること', () => {
let rows;
return driver.get('http://localhost:8080').then(() => {
return driver.wait(() => {
return driver.findElement(By.id('fish-list')).findElements(By.tagName('tr')).then(result => {
rows = result;
return rows.length !== 0;
});
}, 5000);
}).then(() => {
assert(rows.length === 3);
}).then(() => {
return rows[0].findElements(By.tagName('td')).then(cols => {
return cols[1].getText().then(t => {
assert(t === 'まぐろ');
});});}).then(() => {
return rows[1].findElements(By.tagName('td')).then(cols => {
return cols[1].getText().then(t => {
assert(t === 'はまち');
});});}).then(() => {
return rows[2].findElements(By.tagName('td')).then(cols => {
return cols[1].getText().then(t => {
assert(t === 'かつお');
});});});});
26. 実行結果
$ npm test
> case1@0.1.0 test /home/ushiboy/Workspace/niigata.js-v2/case1
> mocha --require test/testSetup.js --recursive './test/spec/*.js'
FishList
✓ 一覧が動的に読み込まれること (573ms)
1 passing (650ms)
27. 28. 29. 30. 注目ポイント
it('一覧が動的に読み込まれること ', async () => {
await driver.get('http://localhost:8080');
let rows;
await driver.wait(async () => {
rows = await driver.findElement(By.id('fish-list')).findElements(By.tagName('tr'));
return rows.length !== 0;
}, 5000);
assert(rows.length === 3);
const cols1 = await rows[0].findElements(By.tagName('td'));
assert(await cols1[1].getText() === 'まぐろ');
const cols2 = await rows[1].findElements(By.tagName('td'));
assert(await cols2[1].getText() === 'はまち');
const cols3 = await rows[2].findElements(By.tagName('td'));
assert(await cols3[1].getText() === 'かつお');
});
31. 32. ベタ書き養殖ものと同じことになっていた
$(function() {
var fish = [];
var selectedItems = [];
$.ajax('fish.json').done(function(response) {
fish = response.fish;
var $fishesList = $('#fish-list');
$.each(fish, function(i, r) {
$fishesList.append(
$('<tr />')
.append($('<td />').append($('<input type="checkbox" class="select-row" />').data(r)))
.append($('<td />').text(r.name))
);
});
});
});
省略
33. 34. Page Object Pattern
● UI(ページ)をページオブジェクトとして抽象化
○ UI操作をメソッドとして扱う
● テストコードとUI操作を分離する
○ UIに変更があった場合に、テスト自体は変更せずにページオブジェクトの変更に留める
● https://www.seleniumhq.org/docs/06_test_design_considerations.jsp#page-ob
ject-design-pattern
35. 36. FishList
const {By, Key, until} = require('selenium-webdriver');
export class FishList {
constructor(driver) {
this.driver = driver;
}
async open() {
await this.driver.get('http://localhost:8080');
return this;
}
async waitForRowToFinishLoading() {
await this.driver.wait(async () => {
const rows = await this.getRows();
return rows.length !== 0;
}, 5000);
return this;
}
async clickSelect() {
await this.driver.findElement(By.id('select-button')).click();
return this.driver.switchTo().alert();
}
async clickAllCheck() {
const check = await this.driver.findElement(By.id('all-check'));
check.click();
return this;
}
async getRows() {
const rows = await this.driver.findElement(By.id('fish-list'))
.findElements(By.tagName('tr'));
return rows.map(r => {
return new FishListRow(this.driver, r);
});
}
}
37. FishListRow
export class FishListRow {
constructor(driver, el) {
this._driver = driver;
this._el = el;
}
async getName() {
const cols = await this._el.findElements(By.tagName('td'));
return cols[1].getText();
}
async clickCheckBox() {
await this._el.findElement(By.className('select-row')).click();
return this;
}
}
38. Page Objectを利用したテストコード
it('一覧が動的に読み込まれること ', async () => {
const p = new FishList(driver);
await p.open();
await p.waitForRowToFinishLoading();
const rows = await p.getRows();
assert(rows.length === 3);
assert(await rows[0].getName() === 'まぐろ');
assert(await rows[1].getName() === 'はまち');
assert(await rows[2].getName() === 'かつお');
});
39. 素朴 vs Page Object Pattern 比較
it('一覧が動的に読み込まれること ', async () => {
await driver.get('http://localhost:8080');
let rows;
await driver.wait(async () => {
rows = await driver.findElement(By.id('fish-list'))
.findElements(By.tagName('tr'));
return rows.length !== 0;
}, 5000);
assert(rows.length === 3);
const cols1 = await rows[0].findElements(By.tagName('td'));
assert(await cols1[1].getText() === 'まぐろ');
const cols2 = await rows[1].findElements(By.tagName('td'));
assert(await cols2[1].getText() === 'はまち');
const cols3 = await rows[2].findElements(By.tagName('td'));
assert(await cols3[1].getText() === 'かつお');
});
it('一覧が動的に読み込まれること ', async () => {
const p = new FishList(driver);
await p.open();
await p.waitForRowToFinishLoading();
const rows = await p.getRows();
assert(rows.length === 3);
assert(await rows[0].getName() === 'まぐろ');
assert(await rows[1].getName() === 'はまち');
assert(await rows[2].getName() === 'かつお');
});
40. 41. 42. 実行結果(複数)
$ npm test
> case1@0.1.0 test /home/ushiboy/Workspace/niigata.js-v2/case1
> mocha --require test/testSetup.js --recursive './test/spec/*.js'
FishList
✓ 一覧が動的に読み込まれること (1161ms)
✓ 未選択状態で"けってい"するとアラートがでること (535ms)
✓ 一覧のアイテムを1件選択して"けってい"すると選択結果が表示されること (604ms)
✓ 一覧のアイテムを複数件選択して "けってい"すると選択結果が表示されること (684ms)
✓ 全体チェックをするとすべてのアイテムが選択されること (731ms)
✓ 全部チェックを外すとすべてのアイテムが選択解除になること (845ms)
6 passing (5s)
43. 44.