SlideShare una empresa de Scribd logo
1 de 44
Descargar para leer sin conexión
ゼロから始めた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環境を立ち上げてワーカーで並列にテスト実行する

Más contenido relacionado

La actualidad más candente

ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計Yoshinori Matsunobu
 
シリコンバレーの「何が」凄いのか
シリコンバレーの「何が」凄いのかシリコンバレーの「何が」凄いのか
シリコンバレーの「何が」凄いのかAtsushi Nakada
 
ドメイン駆動設計をゲーム開発に活かす
ドメイン駆動設計をゲーム開発に活かすドメイン駆動設計をゲーム開発に活かす
ドメイン駆動設計をゲーム開発に活かす増田 亨
 
キーワード駆動によるシステムテストの自動化について 2015
キーワード駆動によるシステムテストの自動化について 2015キーワード駆動によるシステムテストの自動化について 2015
キーワード駆動によるシステムテストの自動化について 2015Toru Koido
 
3週連続DDDその3 ドメイン駆動設計 戦略的設計
3週連続DDDその3  ドメイン駆動設計 戦略的設計3週連続DDDその3  ドメイン駆動設計 戦略的設計
3週連続DDDその3 ドメイン駆動設計 戦略的設計増田 亨
 
Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門Etsuji Nakai
 
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
実運用して分かったRabbit MQの良いところ・気をつけること #jjug実運用して分かったRabbit MQの良いところ・気をつけること #jjug
実運用して分かったRabbit MQの良いところ・気をつけること #jjugYahoo!デベロッパーネットワーク
 
Azure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベント
Azure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベントAzure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベント
Azure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベントShingo Kawahara
 
AWSでDockerを扱うためのベストプラクティス
AWSでDockerを扱うためのベストプラクティスAWSでDockerを扱うためのベストプラクティス
AWSでDockerを扱うためのベストプラクティスAmazon Web Services Japan
 
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステムSEGADevTech
 
なぜ「マイクロサービス“化”」が必要なのか
なぜ「マイクロサービス“化”」が必要なのかなぜ「マイクロサービス“化”」が必要なのか
なぜ「マイクロサービス“化”」が必要なのかYusuke Suzuki
 
アメリカの超巨大クラウドの 「中の人」に転生した ガチ三流プログラマが 米国システム開発の現実を リークする話
アメリカの超巨大クラウドの「中の人」に転生したガチ三流プログラマが米国システム開発の現実をリークする話アメリカの超巨大クラウドの「中の人」に転生したガチ三流プログラマが米国システム開発の現実をリークする話
アメリカの超巨大クラウドの 「中の人」に転生した ガチ三流プログラマが 米国システム開発の現実を リークする話Tsuyoshi Ushio
 
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjugフロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjugItsuki Kuroda
 
Spring Boot ユーザの方のための Quarkus 入門
Spring Boot ユーザの方のための Quarkus 入門Spring Boot ユーザの方のための Quarkus 入門
Spring Boot ユーザの方のための Quarkus 入門tsukasamannen
 
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門増田 亨
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション土岐 孝平
 
いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例Fixstars Corporation
 
ドメイン駆動設計 分析しながら設計する
ドメイン駆動設計 分析しながら設計するドメイン駆動設計 分析しながら設計する
ドメイン駆動設計 分析しながら設計する増田 亨
 
マイクロサービスにおける 非同期アーキテクチャ
マイクロサービスにおける非同期アーキテクチャマイクロサービスにおける非同期アーキテクチャ
マイクロサービスにおける 非同期アーキテクチャota42y
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!mosa siru
 

La actualidad más candente (20)

ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計ソーシャルゲームのためのデータベース設計
ソーシャルゲームのためのデータベース設計
 
シリコンバレーの「何が」凄いのか
シリコンバレーの「何が」凄いのかシリコンバレーの「何が」凄いのか
シリコンバレーの「何が」凄いのか
 
ドメイン駆動設計をゲーム開発に活かす
ドメイン駆動設計をゲーム開発に活かすドメイン駆動設計をゲーム開発に活かす
ドメイン駆動設計をゲーム開発に活かす
 
キーワード駆動によるシステムテストの自動化について 2015
キーワード駆動によるシステムテストの自動化について 2015キーワード駆動によるシステムテストの自動化について 2015
キーワード駆動によるシステムテストの自動化について 2015
 
3週連続DDDその3 ドメイン駆動設計 戦略的設計
3週連続DDDその3  ドメイン駆動設計 戦略的設計3週連続DDDその3  ドメイン駆動設計 戦略的設計
3週連続DDDその3 ドメイン駆動設計 戦略的設計
 
Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門Linux女子部 systemd徹底入門
Linux女子部 systemd徹底入門
 
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
実運用して分かったRabbit MQの良いところ・気をつけること #jjug実運用して分かったRabbit MQの良いところ・気をつけること #jjug
実運用して分かったRabbit MQの良いところ・気をつけること #jjug
 
Azure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベント
Azure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベントAzure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベント
Azure Blob Storageへの様々なアクセス方法を比べてみた JAZUG12周年イベント
 
AWSでDockerを扱うためのベストプラクティス
AWSでDockerを扱うためのベストプラクティスAWSでDockerを扱うためのベストプラクティス
AWSでDockerを扱うためのベストプラクティス
 
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
「龍が如くスタジオ」のQAエンジニアリング技術を結集した全自動バグ取りシステム
 
なぜ「マイクロサービス“化”」が必要なのか
なぜ「マイクロサービス“化”」が必要なのかなぜ「マイクロサービス“化”」が必要なのか
なぜ「マイクロサービス“化”」が必要なのか
 
アメリカの超巨大クラウドの 「中の人」に転生した ガチ三流プログラマが 米国システム開発の現実を リークする話
アメリカの超巨大クラウドの「中の人」に転生したガチ三流プログラマが米国システム開発の現実をリークする話アメリカの超巨大クラウドの「中の人」に転生したガチ三流プログラマが米国システム開発の現実をリークする話
アメリカの超巨大クラウドの 「中の人」に転生した ガチ三流プログラマが 米国システム開発の現実を リークする話
 
フロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjugフロー効率性とリソース効率性について #xpjug
フロー効率性とリソース効率性について #xpjug
 
Spring Boot ユーザの方のための Quarkus 入門
Spring Boot ユーザの方のための Quarkus 入門Spring Boot ユーザの方のための Quarkus 入門
Spring Boot ユーザの方のための Quarkus 入門
 
ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門ドメイン駆動設計のためのオブジェクト指向入門
ドメイン駆動設計のためのオブジェクト指向入門
 
怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション怖くないSpring Bootのオートコンフィグレーション
怖くないSpring Bootのオートコンフィグレーション
 
いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例
 
ドメイン駆動設計 分析しながら設計する
ドメイン駆動設計 分析しながら設計するドメイン駆動設計 分析しながら設計する
ドメイン駆動設計 分析しながら設計する
 
マイクロサービスにおける 非同期アーキテクチャ
マイクロサービスにおける非同期アーキテクチャマイクロサービスにおける非同期アーキテクチャ
マイクロサービスにおける 非同期アーキテクチャ
 
マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!マイクロにしすぎた結果がこれだよ!
マイクロにしすぎた結果がこれだよ!
 

Similar a ゼロから始めた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 a ゼロから始めた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テスト