mocha

Kazuhito Hokamura

2012.07.18

社内勉強会

mochaってなんぞ

ブラウザで使う場合

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Stack Test</title>

<!-- 必要なライブラリ(mohca本体)をダウンロードしてきて読み込む -->
<link rel="stylesheet" href="lib/mocha.css">
<script src="lib/mocha.js"></script>

<!-- mochaのセットアップ -->
<script>
mocha.setup('bdd');
window.onload = function() { mocha.run() };
</script>

<!-- テスト対象のコード -->
<script src="mymodule.js"></script>

<!-- テストコード -->
<script src="test.js"></script>

</head>
<body>

<!-- #mochaのdivを置く -->
<div id="mocha"></div>

</body>
</html>

mochaの基本的な書き方

describe('テストの対象', function() {
  it('テストの内容', function() {
    // ここにテストコードを書く
  });
});
  • describe : テストの対象(ネスト可能)
  • it : テストの内容
  • itの中で例外がthrowされたらテストが失敗する

アサーションについて

  • 値を検証して例外を発生させる機能をアサーションという
  • 大抵のテストライブラリはアサーションをサポートしているがmochaはサポートしていない
  • オススメはexpect.js

expect.jsの例

expect(foo).to.be('bar');
expect(obj).to.eql({ a: 'b' })
expect(num).to.be.a('number');
expect(arr).to.have.length(3);
expect(fn).to.throwError();

mochaとexpect.jsの組み合わせの例

describe('add()', function() {
  it('2つの数値を足した値が返ること', function() {
    expect(add(1, 5)).to.be(6);
  });
});

ケーススタディ

  • Stackというライブラリをつくってテストしてみる
  • テストのサンプルコードでよく登場するライブラリ
  • 簡単な配列みたいな感じ
// 最大要素数が10のスタックをつくる
var stack = new Stack(10);

// push()で追加
stack.push('foo');
stack.push('bar');

// size()で要素数取得
stask.size(); //=> 2

// pop()で要素を取得
stask.pop(); //=> 'bar'

// pop()すると要素は削除される
stask.size(); //=> 1

Stackライブラリの仕様

  • push()でスタックの先頭に文字列を追加できる
  • push()に文字列以外を指定したらエラーになる
  • スタックの最大数をnewの引数で指定できる
  • スタックがいっぱいの時にpush()するとエラーになる
  • pop()でスタックの先頭の値を取得できる
  • スタックが空の状態でpop()したらエラーになる
  • size()で要素数を取得できる
describe('Stack', function() {
});

describe : テストの対象

describe('Stack', function() {
  context('stackが空の場合', function() {
  });

  context('stackがいっぱいの場合', function() {
  });

  context('stackが空でもいっぱいでもない場合', function() {
  });
});

context : テストの状態(describeのエイリアス)

describe('Stack', function() {
  context('stackが空の場合', function() {
    describe('stack#size', function() {
    });

    describe('stack#push', function() {
    });

    describe('stack#pop', function() {
    });
  });

  context('stackがいっぱいの場合', function() {
    describe('stack#size', function() {
    });

    describe('stack#push', function() {
    });

    describe('stack#pop', function() {
    });
  });

  context('stackが空でもいっぱいでもない場合', function() {
    describe('stack#size', function() {
    });

    describe('stack#push', function() {
    });

    describe('stack#pop', function() {
    });
  });
});
describe('Stack', function() {
  context('stackが空の場合', function() {
    describe('stack#size', function() {
    });

    describe('stack#push', function() {
      context('文字列を指定した場合', function() {
      });

      context('非文字列を指定した場合', function() {
      });
    });

    describe('stack#pop', function() {
    });
  });

  ...

});
describe('Stack', function() {
  context('stackが空の場合', function() {
    describe('stack#size', function() {
      it('0を返すこと');
    });

    describe('stack#push', function() {
      context('文字列を指定した場合', function() {
        it('スタックのサイズが1増えること');
      });

      context('非文字列を指定した場合', function() {
        it('エラーになること');
      });
    });

    describe('stack#pop', function() {
      it('エラーになること');
    });
  });

  ...

});
describe('Stack', function() {
  context('stackが空の場合', function() {
    var stack;
    beforeEach(function() {
      stack = new Stack(10);
    });

    describe('stack#size', function() {
      it('0を返すこと');
    });

    describe('stack#push', function() {
      context('文字列を指定した場合', function() {
        it('スタックのサイズが1増えること');
      });

      context('非文字列を指定した場合', function() {
        it('エラーになること');
      });
    });

    describe('stack#pop', function() {
      it('エラーになること');
    });
  });

  ...

});
describe('Stack', function() {
  context('stackが空の場合', function() {
    var stack;
    beforeEach(function() {
      stack = new Stack(10);
    });

    describe('stack#size', function() {
      it('0を返すこと', function() {
        expect(stack.size()).to.be(0);
      });
    });

    describe('stack#push', function() {
      context('文字列を指定した場合', function() {
        it('スタックのサイズが1増えること', function() {
          stack.push('foo');
          expect(stack.size()).to.be(1);
        });
      });

      context('非文字列を指定した場合', function() {
        it('エラーになること', function() {
          expect(function() {
            stack.push(100);
          }).throwError();
        });
      });
    });

    describe('stack#pop', function() {
      it('エラーになること', function() {
        expect(function() {
          stack.pop();
        }).throwError();
      });
    });
  });

  ...

});

まとめ

  • mocha + expect.jsで快適テストライフ(でもライブラリはなんでもいいと思う)
  • describeとcontextを組み合わせるとテスト項目が洗い出しやすい
  • 最初は一個からでもいいからテスト書こう!

Thanks.