java scriptによるテスト駆動開発

43
2013/10/23 中村

Upload: hidekazu-nakamura

Post on 21-May-2015

483 views

Category:

Education


0 download

TRANSCRIPT

Page 1: Java scriptによるテスト駆動開発

2013/10/23 中村

Page 2: Java scriptによるテスト駆動開発

1.テスト駆動開発とは

2. テスト駆動開発の目的

3. テスト駆動開発の流れ

4.テストフレームワークによるテスト

Page 3: Java scriptによるテスト駆動開発

テスト駆動開発(TDD)とは

テスト用プログラムを書く

テストを行う

リファクタリングによるコードの改善

これを繰り返して開発を進める開発手法

Page 4: Java scriptによるテスト駆動開発

プログラムを外部から見た動作を変えずにソースコードの内部構造を整理すること

コードを追加・変更を繰り返していくうちに重複箇所や煩雑になった場合などの対応すること

Page 5: Java scriptによるテスト駆動開発

他の言語と比べてデバッグしにくい事が挙げられる

エラーが発生しても画面から得られる情報が少ない

テストコードを書き、少しづつ開発を進めていくこの手法が向いていると思われる

Page 6: Java scriptによるテスト駆動開発

1.開発が早くなる

2.クロスブラウザテストが簡単に行える

Page 7: Java scriptによるテスト駆動開発

繰り返し自動でテストが行われることで、正常だったプログラムを修正してバグが発生してしまった場合にもすぐに検知できる。

難易度が高い開発の場合、テストコードを短い間隔で記述して実行していくことにより、整理されていく。その結果、早い開発が可能となる。

Page 8: Java scriptによるテスト駆動開発

テスト駆動開発では常にテストが付きまとう。そのテストが思った通りに動作することに気を付けながら開発を進めていく

その結果・・・

着実に進められるため、結果的にバグによる戻り作業の少ない開発が行える

Page 9: Java scriptによるテスト駆動開発

ツールによって引数にブラウザを設定し、そのブラウザを起動してテストを行える

Page 10: Java scriptによるテスト駆動開発

テストコードを書く、ということは初期投資が必要となる。初期投資が回収出来ないような開発では適用すべきではない

Page 11: Java scriptによるテスト駆動開発

テスト駆動開発は以下の作業サイクルを細かく繰り返してプログラミングを進めていく

テストを書く

不合格確認

合格確認

重複削除のためのリファクタリング

Page 12: Java scriptによるテスト駆動開発

実装する機能を選び、そのための単体テストを書く。短く、単一の振る舞いを対象にするべき

Page 13: Java scriptによるテスト駆動開発

テストコードがバグを含んでいる可能性もある

そういった可能性も考慮して、敢えて不合格テストを実施する。不合格テストを実施することでコードの現在の状態を把握する。

Page 14: Java scriptによるテスト駆動開発

テストを成功させる

Page 15: Java scriptによるテスト駆動開発

重複削除などコードをリファクタリングしてきれいにする。

Page 16: Java scriptによるテスト駆動開発

JavaScriptのテストフレームワークはたくさん存在する

参考として以下に例を紹介する

Page 17: Java scriptによるテスト駆動開発

テストを絶えず実行し作業フローにテストを組み込むことが煩わしい

JsUnit 更新が遅く、新しいプロジェクトに適用するには不向き。Prototype.jsライブラリ

のために作られていたこともあり、依存しがち。

YUI Yahooが作成したブラウザ内テストフレームワーク

QUnit jQueryチームが開発。伝統的なxUnitの設計に厳格に従っていない。

Page 18: Java scriptによるテスト駆動開発

コマンドライン上でテストを実行できるが、本番コードが実行されない環境でのテストとなる

Crosscheck 更新されておらず、現在のブラウザでは対応できない

Rhinoとenv.js JQueryを作った方が開発したライブラリ

Page 19: Java scriptによるテスト駆動開発

以下のツールによる開発を紹介する

JsTestDriver 実際のブラウザ、モバイルでもテスト可能

EclipseやIntelliJ IDEAへのプラグインもある

Junitと互換性のあるXMLレポートの出力も可能。Jenkinsとの連携も簡単に対応できる

しかし古いブラウザに対応していない部分もある。

(XMLHttpRequestオブジェクトを必要とするVar.7

以前のIEには対応できない)

Page 20: Java scriptによるテスト駆動開発

4.1サーバーの起動

4.2ブラウザにアクセス

4.3テスト実行

Page 21: Java scriptによるテスト駆動開発

sudo java -jar

$JSTESTDRIVER_HOME/JsTestDri

ver-1.3.5.jar --port 4224

Page 22: Java scriptによるテスト駆動開発

ブラウザで以下のアドレスにアクセス

http://localhost:4224

Page 23: Java scriptによるテスト駆動開発

cd $JSTESTDRIVER_HOME/files/test-

driven-javascript-development-

code/00-main/case01/

sudo java -jar

$JSTESTDRIVER_HOME/JsTestDriver-

1.3.5.jar --tests all

Page 24: Java scriptによるテスト駆動開発

テストリスト:

①4で割り切れる年はうるう年と判定する

②ただし、100で割り切れる年はうるう年でないと判定する

③ただし、400で割り切れる年はうるう年と判定する

Page 25: Java scriptによるテスト駆動開発

①2004年は4で割り切れるため閏年

②2100年は100で割り切れるため閏年でない

③2000年は100で割り切れるが400で割り切れるため閏年

Page 26: Java scriptによるテスト駆動開発

まずは失敗するパターンで実行する

入力データ:7

// main.js

function isLeapYear(year){

jstestdriver.console.log(year

);

if ((year % 4) == 0) {

return true;

}

return false;

}

// isLeapYear.js

TestCase("isLeapYearTest", {

'test isLeapYear':

function(){

var setYears = 7;

assertEquals(true,isLeapYear

(setYears));

}

}

) 入力データ7のケースを追加

Page 27: Java scriptによるテスト駆動開発

Total 1 tests (Passed: 0; Fails: 1; Errors: 0)

(1.00 ms)

Firefox 17.0 Linux: Run 1 tests (Passed: 1;

Fails: 0; Errors 0) (1.00 ms)

isLeapYearTest.test isLeapYear passed

(1.00 ms)

[LOG] 7

Page 28: Java scriptによるテスト駆動開発

次に成功パターンで実行する

入力データ:8

// main.js

function isLeapYear(year){

jstestdriver.console.log(year

);

if ((year % 4) == 0) {

return true;

}

return false;

}

// isLeapYear.js

TestCase("isLeapYearTest", {

'test isLeapYear':

function(){

var setYears = 8;

assertEquals(true,isLeapYear

(setYears));

}

}

)

入力データ8のケースを追加

Page 29: Java scriptによるテスト駆動開発

Total 1 tests (Passed: 1; Fails: 0; Errors: 0)

(1.00 ms)

Firefox 17.0 Linux: Run 1 tests (Passed: 1;

Fails: 0; Errors 0) (1.00 ms)

isLeapYearTest.test isLeapYear passed

(1.00 ms)

[LOG] 8

Page 30: Java scriptによるテスト駆動開発

まずは失敗するパターンで実行する

// main.js

function isLeapYear(year){

jstestdriver.console.log(ye

ar);

if ((year % 4) == 0) {

if (year % 100 == 0) {

return false;

}

return true;

}

return false;

}

// isLeapYear.js

TestCase("isLeapYearTest", {

'test isLeapYear4': function(){

var setYears = 4;

assertEquals(true,isLeapYear(setYears));

},

'test isLeapYear100': function(){

var setYears = 40;

assertEquals(true,isLeapYear(setYears));

},

}

) 入力データ40のケースを追加

両方成功してしまうケース

Page 31: Java scriptによるテスト駆動開発

Total 2 tests (Passed: 2; Fails: 0; Errors: 0)

(0.00 ms)

Firefox 17.0 Linux: Run 2 tests (Passed: 2;

Fails: 0; Errors 0) (0.00 ms)

isLeapYearTest.test isLeapYear4 passed

(0.00 ms)

[LOG] 4

isLeapYearTest.test isLeapYear100 passed

(0.00 ms)

[LOG] 40

Page 32: Java scriptによるテスト駆動開発

あ // main.js

function isLeapYear(year){

jstestdriver.console.log(ye

ar);

if ((year % 4) == 0) {

if (year % 100 == 0) {

return false;

}

return true;

}

return false;

}

// isLeapYear.js

TestCase("isLeapYearTest", {

'test isLeapYear4': function(){

var setYears = 4;

assertEquals(true,isLeapYear(setYears));

},

'test isLeapYear100': function(){

var setYears = 100;

assertEquals(true,isLeapYear(setYears));

},

}

)

入力データ100のケースを追加

こちらは閏年ではないので

Failsで返ってくるはず

Page 33: Java scriptによるテスト駆動開発

Total 2 tests (Passed: 1; Fails: 1; Errors: 0) (1.00 ms)

Firefox 17.0 Linux: Run 2 tests (Passed: 1; Fails: 1; Errors 0) (1.00 ms)

isLeapYearTest.test isLeapYear4 passed (0.00 ms)

[LOG] 4

isLeapYearTest.test isLeapYear100 failed (1.00 ms): AssertError: expected true but was false

.test isLeapYear100@http://localhost:4224/test/test/isLeapYear.js:9

[LOG] 100

Firefox 17.0 Linux: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (0.00 ms)

isLeapYearTest.test isLeapYear4 passed (0.00 ms)

[LOG] 4

isLeapYearTest.test isLeapYear100 passed (0.00 ms)

[LOG] 40

Page 34: Java scriptによるテスト駆動開発

// main.js

function isLeapYear(year){

jstestdriver.console.log(year);

if ((year % 4 == 0) || (year % 100 != 0)) {

return true;

}

return false;

}

Page 35: Java scriptによるテスト駆動開発

// isLeapYear.js

TestCase("isLeapYearTest", {

'test isLeapYear4': function(){

var setYears = 4;

assertEquals(true,isLeapYear(setYea

rs));

},

'test isLeapYear100': function(){

var setYears = 100;

assertEquals(true,isLeapYear(setYea

rs));

},

}

)

// main.js

function isLeapYear(year){

jstestdriver.console.log(yea

r);

if ((year % 4 == 0) ||

(year % 100 != 0)) {

return true;

}

return false;

}

Page 36: Java scriptによるテスト駆動開発

Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (1.00 ms)

Firefox 17.0 Linux: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (1.00 ms)

isLeapYearTest.test isLeapYear4 passed (0.00 ms)

[LOG] 4

isLeapYearTest.test isLeapYear100 passed (1.00 ms)

[LOG] 100

入力データ4は成功(閏年)

入力データ100は失敗(閏年ではない)

となるはず・・・

おかしい

Page 37: Java scriptによるテスト駆動開発

// main.js

function

isLeapYear(year){

jstestdriver.console.log

(year);

if ((year % 4 == 0) &&

(year % 100 != 0)) {

return true;

}

return false;

}

// isLeapYear.js

TestCase("isLeapYearTest", {

'test isLeapYear4': function(){

var setYears = 4;

assertEquals(true,isLeapYear(setYears)

);

},

'test isLeapYear100': function(){

var setYears = 100;

assertEquals(true,isLeapYear(setYears)

);

},

}

)

Page 38: Java scriptによるテスト駆動開発

Total 2 tests (Passed: 1; Fails: 1; Errors: 0) (0.00 ms)

Firefox 17.0 Linux: Run 2 tests (Passed: 1; Fails: 1; Errors 0) (0.00 ms)

isLeapYearTest.test isLeapYear4 passed (0.00 ms)

[LOG] 4

isLeapYearTest.test isLeapYear100 failed (0.00 ms): AssertError: expected true but was false

.test isLeapYear100@http://localhost:4224/test/test/isLeapYear.js:8

[LOG] 100

成功!

Page 39: Java scriptによるテスト駆動開発

// main.js

function isLeapYear(year){

jstestdriver.console.log(ye

ar);

if(year % 400){

return true;

} else if ((year % 4 == 0)

&& (year % 100 != 0)) {

return true;

}

return false;

}

// isLeapYear.js

TestCase("isLeapYearTest", {

'test isLeapYear4': function(){

var setYears = 4;

assertEquals(true,isLeapYear(setYears));

},

'test isLeapYear100': function(){

var setYears = 100;

assertEquals(true,isLeapYear(setYears));

},

'test isLeapYear400': function(){

var setYears = 200;

assertEquals(true,isLeapYear(setYears));

},

}

) 入力データ200のケースを追加

こちらは閏年

Page 40: Java scriptによるテスト駆動開発

Total 3 tests (Passed: 1; Fails: 2; Errors: 0) (1.00 ms)

Firefox 17.0 Linux: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (1.00 ms)

isLeapYearTest.test isLeapYear4 passed (0.00 ms)

[LOG] 4

isLeapYearTest.test isLeapYear100 passed (1.00 ms)

[LOG] 100

isLeapYearTest.test isLeapYear400 passed (0.00 ms)

[LOG] 200

Page 41: Java scriptによるテスト駆動開発

再度テストを行い、成功を確認する

// main.js

function isLeapYear(year){

jstestdriver.console.log(ye

ar);

if (year % 400 == 0 ||

(year % 4 == 0 && year %

100 != 0)) {

return true;

}

return false;

}

// isLeapYear.js

TestCase("isLeapYearTest", {

'test isLeapYear4': function(){

var setYears = 4;

assertEquals(true,isLeapYear(setYears));

},

'test isLeapYear100': function(){

var setYears = 100;

assertEquals(true,isLeapYear(setYears));

},

'test isLeapYear400': function(){

var setYears = 400;

assertEquals(true,isLeapYear(setYears));

},

}

)

Page 42: Java scriptによるテスト駆動開発

Total 3 tests (Passed: 2; Fails: 1; Errors: 0) (2.00 ms)

Firefox 17.0 Linux: Run 3 tests (Passed: 2; Fails: 1; Errors 0) (2.00 ms)

isLeapYearTest.test isLeapYear4 passed (1.00 ms)

[LOG] 4

isLeapYearTest.test isLeapYear100 passed (1.00 ms)

[LOG] 100

isLeapYearTest.test isLeapYear400 failed (0.00 ms): AssertError: expected true but was false

.test isLeapYear400@http://localhost:4224/test/test/isLeapYear.js:13

[LOG] 400

Page 43: Java scriptによるテスト駆動開発

テストを書

不合格確認

合格確認

リファクタリング