blog.koba04.comkoba04's twitter accountkoba04's GitHub account

Karma for JavaScript test runner

2014/06/22 @koba04

karma

今まではなんとなくtestemを使っていたのですが、Karmaを検討する必要があったので試してみました。

サンプルの設定などは↓で見ることが出来ます。

testem to karma

これまでは業務でもtestemを使っていて、テストの数が少ないうち(1000以下)は問題なかったのですが、 段々テストが増えてくるとCPU100%になってテストが走るブラウザが固まることが増えてきて辛い感じになってきました。

そんなときに下記の記事を見て同じような現象だなと思いKarmaを試してみることにしました。

Installation

インストールはnpm install karmaするだけです。

globalでkarmaのコマンドが使いたい場合はgruntのようにnpm install -g karma-cliします。

  • karmaはglobalに入れません。

Easy to use

テストを読み込むためのHTMLを用意して色々書いたりする必要がなくて、karma initしてframeworkやテスト対象のファイルを指定して、 karma startするだけで変更を監視しての自動テストを行うことが出来ます。簡単です。

Configration

最初の設定は、karma initすることで対話的に作成することが出来て、終了するとkarma.conf.jsが作成されます。

ちなみにkarma init karma.conf.coffeeのように拡張子をcoffeeにして指定することでcoffeescriptで作成することも出来ます。

生成されたファイルはこんな感じで、使うフレームワークや対象ファイル、実行するブラウザ、出力形式、ファイルの変更を監視して自動でテストするか、テスト終了後もプロセスを残すかどうかなどを設定します。

  • 設定項目の抜粋
module.exports = function(config) {
  config.set({

    // ベースとなるパス
    basePath: '',

    // 使用するフレームワーク。ここから探せる https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['mocha'],

    // 読み込むファイル(テスト対象のファイルやテストファイルなど)。
    files: ['js/*.js'],

    // filesから除外したファイル
    exclude: [],

    // テストの実行前に差し込む処理。ここから探せる https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {}

    // テストの結果を出力する形式。ここから探せる https://npmjs.org/browse/keyword/karma-reporter
    // 'dots'と'progress'は最初から使える
    reporters: ['progress'],

    // 使用するport
    port: 9876,

    // 出力に色を付けるか
    colors: true,

    // ログレベル: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // ファイルの変更を監視してテストを自動的に実行するかどうか
    autoWatch: true,

    // テストするブラウザ。ここから探せる https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome'],

    // trueにすると一回テストを実行するとプロセスが終了する
    // CIのときに使ったり。
    singleRun: false
  });
};

その他では、autoWatchBatchDelayを使うと指定したms内での変更をまとめて一つとして扱ってくれるので、監視対象のファイルが短い時間に連続して更新されて複数回テストが実行される場合は、この値を長めにするといいかもしれません(defaultは250ms)。

Browsers

ブラウザはChromeやSafariやPhantomJSなど色々ありますので、karma-xxx-launcherで探すことが出来ます。

Frameworks

mochajasminequnitなどの場合はkarma-mochaのようにすでにadapterが用意されているので、 ここにframeworkを設定に書いてadapterをインストールするだけで使うことが出来ます。

karma-mocha-debug

frameworks: ['mocha-debug', 'mocha'],

testem+mochaでやっている時に、ブラウザで結果を確認してそこから指定したテストだけを再実行出来るのが便利だったので karmaでも出来ないないかな思って調べるみると、karma-mocha-debugを使うと出来るようでした。 karmaのブラウザからdebugボタンを押してdebug.htmlを開くと見ることが出来ます。素晴らしい!

karma mocha debug

Preprocessors

preprocessorsを指定することでfilesに書いたファイルに対してテストを実行する前に処理を挟むことが出来、柔軟なテストの設定が可能です。

coffeescriptのコンパイルだったりbrowserifyのビルドなどでkarma-xxxx-preprocessorで探すことが出来ます。

preprocessors: {
  '**/*.coffee': ['coffee']
}

karma-html2js-preprocessor

また、karma-html2js-preprocessorというものもあって、これを使うと指定したHTMLを**window.__html__['name.html']**に入れてくれるので、fixtureデータとして使うことが出来ます。アプリのテストだとどうしてもDOMが必要になるので便利です。

files: [
  '**/*.html'
],
preprocessors: {
  '**/*.html': ['html2js']
},
before ->
  $('body').append window.__html__['fixture.html']

Reporters

reporterを指定することで、様々な形式でテストの結果を出力したり通知したりすることが出来ます。

karma-xxxx-reporterで探すことが出来て、 nyanやtapやmocha形式のような出力形式のカスタマイズ以外にも、結果をgrowlやmp3で通知したりcoverageを計測したりなどさまざまなreporterがあります。

karma-nyan-reporter

reporters: ["nyan"]

nyanの形式でテストを出力してくれるのでもっとテスト書こうという気持ちになっていいです。(バグってたのpull reqして直してもらいました...)

karma nyan reporter

karma-growl-reporter,karma-osx-reporter

reporters: ["growl", "osx"]

GrowlかNotificationCenterでテストの結果を通知してくれるので便利です。

karma-mp3-reporter

https://github.com/x2es/karma-mp3-reporter

成功したとき、失敗したときに好きな音が流せて楽しいですね。

reporters: ["mp3"]

mp3Reporter: {
  red: "go-to-hell.mp3",
  green: "happy.mp3"
}

karma-mocha-reporter

https://github.com/litixsoft/karma-mocha-reporter

mochaの形式で出力してくれるreporterなのですが、describeとitに与える説明をObjectが持っている関数名にすると"Cannot assign to read only property"というエラーになるので注意が必要です(describe "method名"の形式で書いていたのでハマった...)。

# Error!!!!
describe "constructor", ->
  it "xxxx", ->
    ...

原因としては、下記のようにdescriptionをpropertyとして使っているため、constructorやtoStringとかを指定すると関数が取得されて、そこにnameを追加しようとしてエラーになる感じです(use strictが指定されてるためエラーになる)。

path.reduce(function (suite, description, depth) {
            var item = suite[description] || {};
            suite[description] = item;

            item.name = description;

Conclution

というわけでKarmaを試したのですが、思った以上に簡単に始めることが出来て、preprocessorsreportersなどの仕組みがあってプラガブルな感じがとてもいいなぁと思いました。

今後もっとpluginが増えていくことに期待です。

おまけ

power-assert対応しました

もともとbrowserifyを使っていたので、transformにespowerifyを指定してあとはテストをassertに書き換えるだけだったのでとても簡単に出来てよかったです!素晴らしい!

コミットログはこの辺り。 https://github.com/koba04/backbone-boilerplate/commit/2fadec43e46f99cce0d3d828c66d4b12d758f4f0

power-assert