SlideShare a Scribd company logo
1 of 44
Download to read offline
ゼロから始めたE2Eテスト
Niigata.js #2
ushiboy
自己紹介
● 新潟市内でWebプログラマ
● 主にWebフロントエンド担当
○ とある有償フレームワーク
○ React + Redux
● やんごとなき理由でデバイス周りも
○ Raspberry PI + Python
○ ESP32 + C++
今日はE2Eテストの話をします
E2Eテストとは
● End to End テストの略
● システム全体が正しく動作することを確認する
○ Webアプリケーションの場合、ユーザーが行うようにブラウザを操作して結果が期待通りか確認
● 主な特徴
○ コスト高め
○ 実行時間長め
○ 不安定になりやすい
E2Eテストは基本的に辛い
それでもやらなければならない時がある
自分がE2Eテストを始めたきっかけ
● 独りWebフロントエンドチームでSPAなWebアプリケーションを複数開発
○ そこそこの規模の複数アプリ間を機能追加・修正のために行ったり来たり
● 機能追加・修正で気づかずにデグレを入れがちだった
○ 単体テストは書いていたがカバーしきれなかった
○ 使っていたフレームワークの都合上、型システムが使えなかった
● 修正を入れた後にざっと全体確認できるようにしたかった
使ってみたテストツール
● Jasmine + PhantomJS でオレオレ方式
● Karma
● Selenium WebDriver
最終的にSelenium WebDriver
に落ち着いた
ここからは
サンプルアプリケーションを使って
雰囲気を見ていきます
サンプルアプリケーション
● ページロードで動的にJSONデータを取得し
て一覧表示する
● チェックした行を選択アイテムとする
● 「けってい」クリックで選択アイテムを表示
https://ushiboy.github.io/niigata.js-v2/index.html
(余談)アプリのソースは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
テストのための環境を準備
● npmでSelenium WebDriverをインストール
○ $ npm i -D selenium-webdriver
● ブラウザのWebDriverの設置
○ https://www.seleniumhq.org/download/ から取得
● サーバ環境の用意
○ 自分の場合はDockerで構築
● テストコードの用意
○ 自分の場合はmocha + power-assert
WebDriver
● 配布サイト(https://www.seleniumhq.org/download/)から取得
○ ChromeやIE、Edgeなどは各ブラウザ公式が配布している
● OSにインストールされているブラウザのバージョンと合わせる必要がある
○ 昨今のブラウザは自動アップデートされるので動かなくなったらバージョンを疑う
○ プロジェクトのリポジトリ配下に置くなら ignore対象にしたほうが良い
ファイル・ディレクトリ構成
.
├── babel.config.js
├── docker-compose.yml
├── node_modules
├── package-lock.json
├── package.json
└── test
├── driver
│ └── chromedriver
├── spec
│ └── FishList-test.js
└── testSetup.js
WebDriver置き場
Docker用
テストケース置き場
サーバ環境
● 自分の場合はDockerで用意
● 動作に必要なものをまとめて扱うためにdocker-composeを利用
○ nginx
○ DB
○ Redis
○ アプリケーションサーバ
○ etc..
今回のdocker-compose.yml
version: "3"
services:
web:
container_name: "web"
image: nginx:1.17-alpine
ports:
- "8080:80"
volumes:
- ../docs:/usr/share/nginx/html
サーバの起動と終了
$ 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
テストコード
● SeleniumのAPIを使ってページ要素を取得・処理していく
○ https://selenium.dev/selenium/docs/api/javascript/
■ セレクタを使ってDOM要素を取得
■ DOM要素の操作(キー入力・クリックなど)
■ Wait処理
○ 非同期APIを多用
● テストライブラリは非同期なテストに対応しているものを使う
○ 自分の場合mocha
● WebDriver置き場へのパスを通しておく
○ 自分の場合ブートストラップ用の testSetup.jsで
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;
テストコードの基本構成
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 () => {
// テスト内容
});
});
テストケースのコード例
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() === 'かつお');
});
Single Page Applicationなどでのコツ
● 動的に描画を扱うページの場合
○ ページロード後にすべての描画が完了していない
○ 対象の描画完了を待つ必要がある
■ 要素の変化
■ タイマー
● おすすめは要素の変化を利用する
○ タイマーだと十分な余裕を持った間隔がテスト実行の長さに繋がる
○ 一覧であれば行数の変化とか
○ ローディングマスクが消えたタイミングとか
今回のは行数の変化を監視して待つ例
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() === 'かつお');
});
(余談)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 === 'かつお');
});});});});
実行結果
$ 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)
このままテストケースを書いていくと...
発生する問題
● 画面の仕様変更・修正
○ HTMLの構造に変更があった場合、該当するすべてのテストコードを修正する必要がある
● 可読性が悪い
○ テストコードを見るのも直すのもキツくなる
○ そしてテストを動かさなくなる
なぜ問題が発生するのか?
注目ポイント
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() === 'かつお');
});
ページの要素の取得・操作と
テストが一緒になっているから
ベタ書き養殖ものと同じことになっていた
$(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))
);
});
});
});
省略
アプリだけでなくテストでも分離する
Page Object Pattern
● UI(ページ)をページオブジェクトとして抽象化
○ UI操作をメソッドとして扱う
● テストコードとUI操作を分離する
○ UIに変更があった場合に、テスト自体は変更せずにページオブジェクトの変更に留める
● https://www.seleniumhq.org/docs/06_test_design_considerations.jsp#page-ob
ject-design-pattern
今回のアプリケーションでは
FishList
FishListRow
● 全体を扱うFishList
● 行を扱うFishListRow
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);
});
}
}
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;
}
}
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() === 'かつお');
});
素朴 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() === 'かつお');
});
Page Object Patternを採用した結果
● UI変更の修正がしやすくなる
● 可読性上がる
● E2Eテストを書くモチベーションが上がる(個人差あり)
そんな感じでテストを書いて...
実行結果(複数)
$ 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)
まとめ
● E2Eテストは辛い
● 工夫して辛さを抑える
○ Page Object Pattern
● 最後は気合い
付録
● python(pytest)を使ったサンプル
○ https://github.com/ushiboy/niigata.js-v2/tree/master/case2
○ 複数のDocker環境を立ち上げてワーカーで並列にテスト実行する

More Related Content

What's hot

Selenium WebDriver + python で E2Eテスト自動化
Selenium WebDriver + python で E2Eテスト自動化Selenium WebDriver + python で E2Eテスト自動化
Selenium WebDriver + python で E2Eテスト自動化JustSystems Corporation
 
Gaming on aws 〜ゲームにおけるAWS最新活用術〜
Gaming on aws 〜ゲームにおけるAWS最新活用術〜Gaming on aws 〜ゲームにおけるAWS最新活用術〜
Gaming on aws 〜ゲームにおけるAWS最新活用術〜Amazon Web Services Japan
 
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Springドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring増田 亨
 
Redmineプラグイン導入・開発入門
Redmineプラグイン導入・開発入門Redmineプラグイン導入・開発入門
Redmineプラグイン導入・開発入門Minoru Maeda
 
ピクサー USD 入門 新たなコンテンツパイプラインを構築する
ピクサー USD 入門 新たなコンテンツパイプラインを構築するピクサー USD 入門 新たなコンテンツパイプラインを構築する
ピクサー USD 入門 新たなコンテンツパイプラインを構築するTakahito Tejima
 
View Customize Pluginで出来ること
View Customize Pluginで出来ることView Customize Pluginで出来ること
View Customize Pluginで出来ることonozaty
 
インフラエンジニアの綺麗で優しい手順書の書き方
インフラエンジニアの綺麗で優しい手順書の書き方インフラエンジニアの綺麗で優しい手順書の書き方
インフラエンジニアの綺麗で優しい手順書の書き方Shohei Koyama
 
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps Online
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps OnlineGoogle Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps Online
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps OnlineGoogle Cloud Platform - Japan
 
大規模ゲーム開発における build 高速化と安定化
大規模ゲーム開発における build 高速化と安定化大規模ゲーム開発における build 高速化と安定化
大規模ゲーム開発における build 高速化と安定化DeNA
 
アーキテクチャのレビューについて - JaSST Review '18
アーキテクチャのレビューについて - JaSST Review '18アーキテクチャのレビューについて - JaSST Review '18
アーキテクチャのレビューについて - JaSST Review '18Yusuke Suzuki
 
他社製品と比較した際のAuth0のいいところ
他社製品と比較した際のAuth0のいいところ他社製品と比較した際のAuth0のいいところ
他社製品と比較した際のAuth0のいいところSatoshi Takayanagi
 
SSRF対策としてAmazonから発表されたIMDSv2の効果と破り方
SSRF対策としてAmazonから発表されたIMDSv2の効果と破り方SSRF対策としてAmazonから発表されたIMDSv2の効果と破り方
SSRF対策としてAmazonから発表されたIMDSv2の効果と破り方Hiroshi Tokumaru
 
Redmineのバージョンアップに追従していくための一工夫
Redmineのバージョンアップに追従していくための一工夫Redmineのバージョンアップに追従していくための一工夫
Redmineのバージョンアップに追従していくための一工夫Go Maeda
 
CircleCIのinfrastructureを支えるTerraformのCI/CDパイプラインの改善
CircleCIのinfrastructureを支えるTerraformのCI/CDパイプラインの改善CircleCIのinfrastructureを支えるTerraformのCI/CDパイプラインの改善
CircleCIのinfrastructureを支えるTerraformのCI/CDパイプラインの改善Ito Takayuki
 
Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)
Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)
Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)NTT DATA Technology & Innovation
 

What's hot (20)

Selenium WebDriver + python で E2Eテスト自動化
Selenium WebDriver + python で E2Eテスト自動化Selenium WebDriver + python で E2Eテスト自動化
Selenium WebDriver + python で E2Eテスト自動化
 
Gaming on aws 〜ゲームにおけるAWS最新活用術〜
Gaming on aws 〜ゲームにおけるAWS最新活用術〜Gaming on aws 〜ゲームにおけるAWS最新活用術〜
Gaming on aws 〜ゲームにおけるAWS最新活用術〜
 
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Springドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
ドメインロジックに集中せよ 〜ドメイン駆動設計 powered by Spring
 
Redmineプラグイン導入・開発入門
Redmineプラグイン導入・開発入門Redmineプラグイン導入・開発入門
Redmineプラグイン導入・開発入門
 
Epic Online Services でできること
Epic Online Services でできることEpic Online Services でできること
Epic Online Services でできること
 
今さら聞けない人のためのCI/CD超入門
今さら聞けない人のためのCI/CD超入門今さら聞けない人のためのCI/CD超入門
今さら聞けない人のためのCI/CD超入門
 
ピクサー USD 入門 新たなコンテンツパイプラインを構築する
ピクサー USD 入門 新たなコンテンツパイプラインを構築するピクサー USD 入門 新たなコンテンツパイプラインを構築する
ピクサー USD 入門 新たなコンテンツパイプラインを構築する
 
View Customize Pluginで出来ること
View Customize Pluginで出来ることView Customize Pluginで出来ること
View Customize Pluginで出来ること
 
インフラエンジニアの綺麗で優しい手順書の書き方
インフラエンジニアの綺麗で優しい手順書の書き方インフラエンジニアの綺麗で優しい手順書の書き方
インフラエンジニアの綺麗で優しい手順書の書き方
 
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps Online
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps OnlineGoogle Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps Online
Google Cloud Game Servers 徹底入門 | 第 10 回 Google Cloud INSIDE Games & Apps Online
 
大規模ゲーム開発における build 高速化と安定化
大規模ゲーム開発における build 高速化と安定化大規模ゲーム開発における build 高速化と安定化
大規模ゲーム開発における build 高速化と安定化
 
アーキテクチャのレビューについて - JaSST Review '18
アーキテクチャのレビューについて - JaSST Review '18アーキテクチャのレビューについて - JaSST Review '18
アーキテクチャのレビューについて - JaSST Review '18
 
他社製品と比較した際のAuth0のいいところ
他社製品と比較した際のAuth0のいいところ他社製品と比較した際のAuth0のいいところ
他社製品と比較した際のAuth0のいいところ
 
SSRF対策としてAmazonから発表されたIMDSv2の効果と破り方
SSRF対策としてAmazonから発表されたIMDSv2の効果と破り方SSRF対策としてAmazonから発表されたIMDSv2の効果と破り方
SSRF対策としてAmazonから発表されたIMDSv2の効果と破り方
 
Redmineのバージョンアップに追従していくための一工夫
Redmineのバージョンアップに追従していくための一工夫Redmineのバージョンアップに追従していくための一工夫
Redmineのバージョンアップに追従していくための一工夫
 
OSSを活用したIaCの実現
OSSを活用したIaCの実現OSSを活用したIaCの実現
OSSを活用したIaCの実現
 
Serverless時代のJavaについて
Serverless時代のJavaについてServerless時代のJavaについて
Serverless時代のJavaについて
 
CircleCIのinfrastructureを支えるTerraformのCI/CDパイプラインの改善
CircleCIのinfrastructureを支えるTerraformのCI/CDパイプラインの改善CircleCIのinfrastructureを支えるTerraformのCI/CDパイプラインの改善
CircleCIのinfrastructureを支えるTerraformのCI/CDパイプラインの改善
 
Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)
Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)
Kubernetes環境に対する性能試験(Kubernetes Novice Tokyo #2 発表資料)
 
5分でわかる Sensor SDK
5分でわかる Sensor SDK5分でわかる Sensor SDK
5分でわかる Sensor SDK
 

Similar to ゼロから始めたE2Eテスト

Tokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテストTokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテストYohei Sato
 
13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejsTakayoshi Tanaka
 
React Native GUIDE
React Native GUIDEReact Native GUIDE
React Native GUIDEdcubeio
 
React.jsでクライアントサイドなWebアプリ入門
React.jsでクライアントサイドなWebアプリ入門React.jsでクライアントサイドなWebアプリ入門
React.jsでクライアントサイドなWebアプリ入門spring_raining
 
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~normalian
 
TDD勉強会キックオフ for Java
TDD勉強会キックオフ for JavaTDD勉強会キックオフ for Java
TDD勉強会キックオフ for JavaYuta Kawadai
 
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶjQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶShumpei Shiraishi
 
Monadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
Monadic Programmingのススメ - Functional Reactive ProgrammingへのアプローチMonadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
Monadic Programmingのススメ - Functional Reactive ProgrammingへのアプローチTomoharu ASAMI
 
はじめてのAngular その1
はじめてのAngular その1はじめてのAngular その1
はじめてのAngular その1純一 榮枝
 
Parse.comと始めるBackbone.js入門(jscafe7)
Parse.comと始めるBackbone.js入門(jscafe7)Parse.comと始めるBackbone.js入門(jscafe7)
Parse.comと始めるBackbone.js入門(jscafe7)Ryuma Tsukano
 
究極のバッチフレームワーク(予定)
究極のバッチフレームワーク(予定)究極のバッチフレームワーク(予定)
究極のバッチフレームワーク(予定)fumoto kazuhiro
 
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜JustSystems Corporation
 
Unit testで定時帰宅!
Unit testで定時帰宅!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)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 大域関数の行方から #swift2symposiumSwift 2.0 大域関数の行方から #swift2symposium
Swift 2.0 大域関数の行方から #swift2symposiumTomohiro Kumagai
 
130710 02
130710 02130710 02
130710 02openrtm
 
Archive: Android アプリ開発入門(2015/6/19 社内勉強会)
Archive: Android アプリ開発入門(2015/6/19 社内勉強会)Archive: Android アプリ開発入門(2015/6/19 社内勉強会)
Archive: Android アプリ開発入門(2015/6/19 社内勉強会)Yoko TAMADA
 
第4回勉強会 単体テストのすすめ
第4回勉強会 単体テストのすすめ第4回勉強会 単体テストのすすめ
第4回勉強会 単体テストのすすめhakoika-itwg
 

Similar to ゼロから始めたE2Eテスト (20)

Tokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテストTokyor14 - R言語でユニットテスト
Tokyor14 - R言語でユニットテスト
 
13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs13016 n分で作るtype scriptでnodejs
13016 n分で作るtype scriptでnodejs
 
React Native GUIDE
React Native GUIDEReact Native GUIDE
React Native GUIDE
 
React.jsでクライアントサイドなWebアプリ入門
React.jsでクライアントサイドなWebアプリ入門React.jsでクライアントサイドなWebアプリ入門
React.jsでクライアントサイドなWebアプリ入門
 
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
基礎から見直す ASP.NET MVC の単体テスト自動化方法 ~ Windows Azure 関連もあるかも~
 
Spring と TDD
Spring と TDDSpring と TDD
Spring と TDD
 
Ll xcode
Ll xcodeLl xcode
Ll xcode
 
TDD勉強会キックオフ for Java
TDD勉強会キックオフ for JavaTDD勉強会キックオフ for Java
TDD勉強会キックオフ for Java
 
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶjQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
 
Monadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
Monadic Programmingのススメ - Functional Reactive ProgrammingへのアプローチMonadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
Monadic Programmingのススメ - Functional Reactive Programmingへのアプローチ
 
はじめてのAngular その1
はじめてのAngular その1はじめてのAngular その1
はじめてのAngular その1
 
Parse.comと始めるBackbone.js入門(jscafe7)
Parse.comと始めるBackbone.js入門(jscafe7)Parse.comと始めるBackbone.js入門(jscafe7)
Parse.comと始めるBackbone.js入門(jscafe7)
 
究極のバッチフレームワーク(予定)
究極のバッチフレームワーク(予定)究極のバッチフレームワーク(予定)
究極のバッチフレームワーク(予定)
 
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
Javaチョットデキルへの道〜JavaコアSDKに見る真似したいコード10選〜
 
Unit testで定時帰宅!
Unit testで定時帰宅!Unit testで定時帰宅!
Unit testで定時帰宅!
 
C# 8.0 Preview in Visual Studio 2019 (16.0)
C# 8.0 Preview in Visual Studio 2019 (16.0)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 大域関数の行方から #swift2symposiumSwift 2.0 大域関数の行方から #swift2symposium
Swift 2.0 大域関数の行方から #swift2symposium
 
130710 02
130710 02130710 02
130710 02
 
Archive: Android アプリ開発入門(2015/6/19 社内勉強会)
Archive: Android アプリ開発入門(2015/6/19 社内勉強会)Archive: Android アプリ開発入門(2015/6/19 社内勉強会)
Archive: Android アプリ開発入門(2015/6/19 社内勉強会)
 
第4回勉強会 単体テストのすすめ
第4回勉強会 単体テストのすすめ第4回勉強会 単体テストのすすめ
第4回勉強会 単体テストのすすめ
 

ゼロから始めたE2Eテスト