Enviar búsqueda
Cargar
ゼロから始めたE2Eテスト
•
2 recomendaciones
•
3,578 vistas
ushiboy
Seguir
Niigata.js #2 発表資料
Leer menos
Leer más
Ingeniería
Denunciar
Compartir
Denunciar
Compartir
1 de 44
Descargar ahora
Descargar para leer sin conexión
Recomendados
「龍が如く7 光と闇の行方」の自動テスト活用事例とテスト自動化チーム(仮)による若手育成の取り組みについて
「龍が如く7 光と闇の行方」の自動テスト活用事例とテスト自動化チーム(仮)による若手育成の取り組みについて
SEGADevTech
イベント・ソーシングを知る
イベント・ソーシングを知る
Shuhei Fujita
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
Atsushi Nakamura
オススメの標準・準標準パッケージ20選
オススメの標準・準標準パッケージ20選
Takuya Ueda
第1回 GPT / ジェネレーティブAI 勉強会「ChatGPTでMML音楽を奏でてみた&LLMで思うこと」
第1回 GPT / ジェネレーティブAI 勉強会「ChatGPTでMML音楽を奏でてみた&LLMで思うこと」
嶋 是一 (Yoshikazu SHIMA)
ジャストシステムJava100本ノックのご紹介
ジャストシステムJava100本ノックのご紹介
JustSystems Corporation
Ruby向け帳票ソリューション「ThinReports」の開発で知るOSSの威力
Ruby向け帳票ソリューション「ThinReports」の開発で知るOSSの威力
ThinReports
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
Amazon Web Services Japan
Recomendados
「龍が如く7 光と闇の行方」の自動テスト活用事例とテスト自動化チーム(仮)による若手育成の取り組みについて
「龍が如く7 光と闇の行方」の自動テスト活用事例とテスト自動化チーム(仮)による若手育成の取り組みについて
SEGADevTech
イベント・ソーシングを知る
イベント・ソーシングを知る
Shuhei Fujita
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
Atsushi Nakamura
オススメの標準・準標準パッケージ20選
オススメの標準・準標準パッケージ20選
Takuya Ueda
第1回 GPT / ジェネレーティブAI 勉強会「ChatGPTでMML音楽を奏でてみた&LLMで思うこと」
第1回 GPT / ジェネレーティブAI 勉強会「ChatGPTでMML音楽を奏でてみた&LLMで思うこと」
嶋 是一 (Yoshikazu SHIMA)
ジャストシステムJava100本ノックのご紹介
ジャストシステムJava100本ノックのご紹介
JustSystems Corporation
Ruby向け帳票ソリューション「ThinReports」の開発で知るOSSの威力
Ruby向け帳票ソリューション「ThinReports」の開発で知るOSSの威力
ThinReports
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
AWS Black Belt Online Seminar 2018 Amazon DynamoDB Advanced Design Pattern
Amazon Web Services Japan
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
Yoshinori Matsunobu
シリコンバレーの「何が」凄いのか
シリコンバレーの「何が」凄いのか
Atsushi Nakada
ドメイン駆動設計をゲーム開発に活かす
ドメイン駆動設計をゲーム開発に活かす
増田 亨
キーワード駆動によるシステムテストの自動化について 2015
キーワード駆動によるシステムテストの自動化について 2015
Toru Koido
3週連続DDDその3 ドメイン駆動設計 戦略的設計
3週連続DDDその3 ドメイン駆動設計 戦略的設計
増田 亨
Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門
Etsuji Nakai
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
Yahoo!デベロッパーネットワーク
Azure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベント
Azure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベント
Shingo Kawahara
AWSでDockerを扱うためのベストプラクティス
AWSでDockerを扱うためのベストプラクティス
Amazon Web Services Japan
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
SEGADevTech
なぜ「マイクロサービス“化”」が必要なのか
なぜ「マイクロサービス“化”」が必要なのか
Yusuke Suzuki
アメリカの超巨大クラウドの「中の人」に転生したガチ三流プログラマが米国システム開発の現実をリークする話
アメリカの超巨大クラウドの「中の人」に転生したガチ三流プログラマが米国システム開発の現実をリークする話
Tsuyoshi Ushio
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjug
Itsuki Kuroda
Spring Boot ユーザの方のための Quarkus 入門
Spring Boot ユーザの方のための Quarkus 入門
tsukasamannen
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門
増田 亨
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
土岐 孝平
いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例
Fixstars Corporation
ドメイン駆動設計 分析しながら設計する
ドメイン駆動設計 分析しながら設計する
増田 亨
マイクロサービスにおける非同期アーキテクチャ
マイクロサービスにおける非同期アーキテクチャ
ota42y
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
mosa siru
Tokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテスト
Yohei Sato
13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs
Takayoshi Tanaka
Más contenido relacionado
La actualidad más candente
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
Yoshinori Matsunobu
シリコンバレーの「何が」凄いのか
シリコンバレーの「何が」凄いのか
Atsushi Nakada
ドメイン駆動設計をゲーム開発に活かす
ドメイン駆動設計をゲーム開発に活かす
増田 亨
キーワード駆動によるシステムテストの自動化について 2015
キーワード駆動によるシステムテストの自動化について 2015
Toru Koido
3週連続DDDその3 ドメイン駆動設計 戦略的設計
3週連続DDDその3 ドメイン駆動設計 戦略的設計
増田 亨
Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門
Etsuji Nakai
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
Yahoo!デベロッパーネットワーク
Azure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベント
Azure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベント
Shingo Kawahara
AWSでDockerを扱うためのベストプラクティス
AWSでDockerを扱うためのベストプラクティス
Amazon Web Services Japan
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
SEGADevTech
なぜ「マイクロサービス“化”」が必要なのか
なぜ「マイクロサービス“化”」が必要なのか
Yusuke Suzuki
アメリカの超巨大クラウドの「中の人」に転生したガチ三流プログラマが米国システム開発の現実をリークする話
アメリカの超巨大クラウドの「中の人」に転生したガチ三流プログラマが米国システム開発の現実をリークする話
Tsuyoshi Ushio
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjug
Itsuki Kuroda
Spring Boot ユーザの方のための Quarkus 入門
Spring Boot ユーザの方のための Quarkus 入門
tsukasamannen
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門
増田 亨
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
土岐 孝平
いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例
Fixstars Corporation
ドメイン駆動設計 分析しながら設計する
ドメイン駆動設計 分析しながら設計する
増田 亨
マイクロサービスにおける非同期アーキテクチャ
マイクロサービスにおける非同期アーキテクチャ
ota42y
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
mosa siru
La actualidad más candente
(20)
ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
シリコンバレーの「何が」凄いのか
シリコンバレーの「何が」凄いのか
ドメイン駆動設計をゲーム開発に活かす
ドメイン駆動設計をゲーム開発に活かす
キーワード駆動によるシステムテストの自動化について 2015
キーワード駆動によるシステムテストの自動化について 2015
3週連続DDDその3 ドメイン駆動設計 戦略的設計
3週連続DDDその3 ドメイン駆動設計 戦略的設計
Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
Azure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベント
Azure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベント
AWSでDockerを扱うためのベストプラクティス
AWSでDockerを扱うためのベストプラクティス
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
なぜ「マイクロサービス“化”」が必要なのか
なぜ「マイクロサービス“化”」が必要なのか
アメリカの超巨大クラウドの「中の人」に転生したガチ三流プログラマが米国システム開発の現実をリークする話
アメリカの超巨大クラウドの「中の人」に転生したガチ三流プログラマが米国システム開発の現実をリークする話
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjug
Spring Boot ユーザの方のための Quarkus 入門
Spring Boot ユーザの方のための Quarkus 入門
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例
ドメイン駆動設計 分析しながら設計する
ドメイン駆動設計 分析しながら設計する
マイクロサービスにおける非同期アーキテクチャ
マイクロサービスにおける非同期アーキテクチャ
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
Similar a ゼロから始めたE2Eテスト
Tokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテスト
Yohei Sato
13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs
Takayoshi Tanaka
React Native GUIDE
React Native GUIDE
dcubeio
React.jsでクライアントサイドなWebアプリ入門
React.jsでクライアントサイドなWebアプリ入門
spring_raining
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
normalian
Spring と TDD
Spring と TDD
Takeshi Ogawa
Ll xcode
Ll xcode
Net Kanayan
TDD勉強会キックオフ for Java
TDD勉強会キックオフ for Java
Yuta Kawadai
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
Shumpei Shiraishi
Monadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
Monadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
Tomoharu ASAMI
はじめてのAngular その1
はじめてのAngular その1
純一 榮枝
Parse.comと始めるBackbone.js入門(jscafe7)
Parse.comと始めるBackbone.js入門(jscafe7)
Ryuma Tsukano
究極のバッチフレームワーク(予定)
究極のバッチフレームワーク(予定)
fumoto kazuhiro
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
JustSystems Corporation
Unit testで定時帰宅!
Unit testで定時帰宅!
Funato Takashi
C# 8.0 Preview in Visual Studio 2019 (16.0)
C# 8.0 Preview in Visual Studio 2019 (16.0)
信之 岩永
Swift 2.0 大域関数の行方から #swift2symposium
Swift 2.0 大域関数の行方から #swift2symposium
Tomohiro Kumagai
130710 02
130710 02
openrtm
Archive: Android アプリ開発入門(2015/6/19 社内勉強会)
Archive: Android アプリ開発入門(2015/6/19 社内勉強会)
Yoko TAMADA
第4回勉強会 単体テストのすすめ
第4回勉強会 単体テストのすすめ
hakoika-itwg
Similar a ゼロから始めたE2Eテスト
(20)
Tokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテスト
13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs
React Native GUIDE
React Native GUIDE
React.jsでクライアントサイドなWebアプリ入門
React.jsでクライアントサイドなWebアプリ入門
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
Spring と TDD
Spring と TDD
Ll xcode
Ll xcode
TDD勉強会キックオフ for Java
TDD勉強会キックオフ for Java
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
Monadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
Monadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
はじめてのAngular その1
はじめてのAngular その1
Parse.comと始めるBackbone.js入門(jscafe7)
Parse.comと始めるBackbone.js入門(jscafe7)
究極のバッチフレームワーク(予定)
究極のバッチフレームワーク(予定)
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
Unit testで定時帰宅!
Unit testで定時帰宅!
C# 8.0 Preview in Visual Studio 2019 (16.0)
C# 8.0 Preview in Visual Studio 2019 (16.0)
Swift 2.0 大域関数の行方から #swift2symposium
Swift 2.0 大域関数の行方から #swift2symposium
130710 02
130710 02
Archive: Android アプリ開発入門(2015/6/19 社内勉強会)
Archive: Android アプリ開発入門(2015/6/19 社内勉強会)
第4回勉強会 単体テストのすすめ
第4回勉強会 単体テストのすすめ
ゼロから始めたE2Eテスト
1.
ゼロから始めたE2Eテスト Niigata.js #2 ushiboy
2.
自己紹介 ● 新潟市内でWebプログラマ ● 主にWebフロントエンド担当 ○
とある有償フレームワーク ○ React + Redux ● やんごとなき理由でデバイス周りも ○ Raspberry PI + Python ○ ESP32 + C++
3.
今日はE2Eテストの話をします
4.
E2Eテストとは ● End to
End テストの略 ● システム全体が正しく動作することを確認する ○ Webアプリケーションの場合、ユーザーが行うようにブラウザを操作して結果が期待通りか確認 ● 主な特徴 ○ コスト高め ○ 実行時間長め ○ 不安定になりやすい
5.
E2Eテストは基本的に辛い
6.
それでもやらなければならない時がある
7.
自分がE2Eテストを始めたきっかけ ● 独りWebフロントエンドチームでSPAなWebアプリケーションを複数開発 ○ そこそこの規模の複数アプリ間を機能追加・修正のために行ったり来たり ●
機能追加・修正で気づかずにデグレを入れがちだった ○ 単体テストは書いていたがカバーしきれなかった ○ 使っていたフレームワークの都合上、型システムが使えなかった ● 修正を入れた後にざっと全体確認できるようにしたかった
8.
使ってみたテストツール ● Jasmine +
PhantomJS でオレオレ方式 ● Karma ● Selenium WebDriver
9.
最終的にSelenium WebDriver に落ち着いた
10.
ここからは サンプルアプリケーションを使って 雰囲気を見ていきます
11.
サンプルアプリケーション ● ページロードで動的にJSONデータを取得し て一覧表示する ● チェックした行を選択アイテムとする ●
「けってい」クリックで選択アイテムを表示 https://ushiboy.github.io/niigata.js-v2/index.html
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.
テストのための環境を準備 ● npmでSelenium WebDriverをインストール ○
$ npm i -D selenium-webdriver ● ブラウザのWebDriverの設置 ○ https://www.seleniumhq.org/download/ から取得 ● サーバ環境の用意 ○ 自分の場合はDockerで構築 ● テストコードの用意 ○ 自分の場合はmocha + power-assert
14.
WebDriver ● 配布サイト(https://www.seleniumhq.org/download/)から取得 ○ ChromeやIE、Edgeなどは各ブラウザ公式が配布している ●
OSにインストールされているブラウザのバージョンと合わせる必要がある ○ 昨今のブラウザは自動アップデートされるので動かなくなったらバージョンを疑う ○ プロジェクトのリポジトリ配下に置くなら ignore対象にしたほうが良い
15.
ファイル・ディレクトリ構成 . ├── babel.config.js ├── docker-compose.yml ├──
node_modules ├── package-lock.json ├── package.json └── test ├── driver │ └── chromedriver ├── spec │ └── FishList-test.js └── testSetup.js WebDriver置き場 Docker用 テストケース置き場
16.
サーバ環境 ● 自分の場合はDockerで用意 ● 動作に必要なものをまとめて扱うためにdocker-composeを利用 ○
nginx ○ DB ○ Redis ○ アプリケーションサーバ ○ etc..
17.
今回のdocker-compose.yml version: "3" services: web: container_name: "web" image:
nginx:1.17-alpine ports: - "8080:80" volumes: - ../docs:/usr/share/nginx/html
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.
テストコード ● SeleniumのAPIを使ってページ要素を取得・処理していく ○ https://selenium.dev/selenium/docs/api/javascript/ ■
セレクタを使ってDOM要素を取得 ■ DOM要素の操作(キー入力・クリックなど) ■ Wait処理 ○ 非同期APIを多用 ● テストライブラリは非同期なテストに対応しているものを使う ○ 自分の場合mocha ● WebDriver置き場へのパスを通しておく ○ 自分の場合ブートストラップ用の testSetup.jsで
20.
testSetup.js require('@babel/register')(); require('@babel/polyfill'); const path =
require('path'); const driversDirPath = path.join(__dirname, 'driver'); process.env.PATH = process.env.PATH + ':' + driversDirPath;
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.
発生する問題 ● 画面の仕様変更・修正 ○ HTMLの構造に変更があった場合、該当するすべてのテストコードを修正する必要がある ●
可読性が悪い ○ テストコードを見るのも直すのもキツくなる ○ そしてテストを動かさなくなる
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.
今回のアプリケーションでは FishList FishListRow ● 全体を扱うFishList ● 行を扱うFishListRow
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.
Page Object Patternを採用した結果 ●
UI変更の修正がしやすくなる ● 可読性上がる ● E2Eテストを書くモチベーションが上がる(個人差あり)
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.
まとめ ● E2Eテストは辛い ● 工夫して辛さを抑える ○
Page Object Pattern ● 最後は気合い
44.
付録 ● python(pytest)を使ったサンプル ○ https://github.com/ushiboy/niigata.js-v2/tree/master/case2 ○
複数のDocker環境を立ち上げてワーカーで並列にテスト実行する
Descargar ahora