15 min/d

ぼうずやのにっき

mochaで重複コードの排除をためした

mochaで重複コードの排除をためした。

bouzuya/node-backlog-apiのpromiseパターンを適用しようとしているのだけれど、それにともなってテストコードを見直している。

node-backlog-apiのテストコードは相当にひどい。いろいろとひどい点はあるのだけれど、重複コードがひどい。例えば、expectの準備だったり、テストサーバーを立ち上げるコードが各ファイルに記述してあって、見事なまでに重複している。もちろん、API呼び出しのハンドラーは違うのだけど、明らかな重複だ。これは相当にひどい。

そこで重複コードの排除を考えた。

今回からexpect.jschaiのbdd style(expect)に置き換えようと考えているので、次のような記述が必要になる。

var expect = require('chai').use(require('chai-sinon')).expect;

そして、先に書いたようなテストサーバーを立ち上げるbeforeEachも必要である。

これらを簡潔にセットアップしてくれる記述がしたい。Ruby on Railsほかの例にならってhelperを準備することにした。

test/helper.jsを用意し、各ファイルからは次の1行を書くだけでOKという状態にする。

require('./helper');

例えばtest/helper.jsの内容は次のようになる。

global.expect = require('chai').use(require('sinon-chai')).expect;

var xmlrpc = require('xmlrpc');
var backlog = require('../');

beforeEach(function(done) {
  global.server = xmlrpc.createServer({
    host: 'localhost',
    port: 3000
  }, function() {
    global.client = backlog();
    client._client = function() {
      return xmlrpc.createClient({
        url: 'http://localhost:3000/XML-RPC'
      });
    };
    done();
  });
});

afterEach(function(done) {
  global.server.close(done);
});

globalにexpect,server,clientを設定している。expectはともかく、ほかは本来設定しなくても良いのだけれど、既存コードがserverという変数名ですべて使っていて、それを置換しても見にくいので、このようにした。プロダクトコードではダメだけどね。

mochaはroot hookというのが可能で、describeの中だけでなくrootでbeforeEachなどを設定できる。これはすべてのテストに対して動く。

最初の構想ではrequire('./helper');も重複なので排除したかった。mochaには--requireというオプションが準備されていて、テスト実行前に共通でrequireしてくれるのだけれど、--requireで指定されたファイル中ではbeforeEachは設定することができないため、今回はこのような記述になっている。

この重複の排除のおかげで、テストコードの見た目はかなり良くなった。

またsinon.jsを使う(require('chai-sinon'))ことでテストダブルの扱いもかなり良くなっている。今週はmochaでのテスト力が上がっているように感じる。明日はこの修正をおえて、node-backlog-apiの新バージョンをリリースしたい。