2017/05/22

Karma+mocha+chaiでNode.jsとブラウザで同じコードでテストする

Node.jsでもブラウザでも使えるライブラリを作っているときに、「どちらも同じテストコード(同一ファイル)を使って実行できないかなぁ?」と思い、いろいろ調べた。

Karmaがフロントエンドのテストツールで有名なので、これを使ってみる。
また、テストコードについては使い慣れているmocha+chaiのセットで書く。
(mocha+power-assertとかJasmineとかでもできるけど…)

環境・ディレクトリ構成


以下の環境で行う。

  • Node.js - v6.10.2
  • mocha - v3.3.0
  • chai - v3.5.0
  • karma - v1.7.0

ディレクトリ構成は以下のとおり。
.
├── node_modules
├── karma.conf.js  // karma用設定ファイル(あとで作成する)
├── package.json
├── src
│   └── app.js  // テスト対象のコード
└── test
    └── spec.js  // テストコード

次に、必要なものをインストールする。
# とりあえず必要なもの
$ npm i -D karma mocha chai

# テストコードのrequireを解決するために必要なもの(これがないと`ReferenceError: require is not defined`になる)
$ npm i -D karma-browserify browserify watchify

# karma.conf.jsを作ってくれる
$ npm i -g karma-cli



Karmaの設定を行う


さきほどインストールしたkarma-cliを使うことで、設定ファイル(karma.conf.js)を生成できる。
$ karma init
# 使用するテストフレームワークを選択する
Which testing framework do you want to use ?
Press tab to list possible options. Enter to move to the next question.
> mocha

# Require.jsを使うか?(今回はbrowserifyを使うのでno)
Do you want to use Require.js ?
This will add Require.js plugin.
Press tab to list possible options. Enter to move to the next question.
> no

# テストするブラウザ(ChromeとFirefoxを選択、必要に応じてIEとかSafariとか追加)
Do you want to capture any browsers automatically ?
Press tab to list possible options. Enter empty string to move to the next question.
> Chrome
> Firefox
>

# 読み込むファイルとテストファイルについて
# 読み込むファイルは、Browserify使うので気にしない
# テストは `./test`ディレクトリに`hoge.js`を入れるので、`test/**/*.js`
What is the location of your source and test files ?
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.
> test/**/*.js
>

# ↑で指定したパターンから除外したいものがあるときに指定
Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
Enter empty string to move to the next question.
>

# ファイルの変更をwatchして自動でテストを実行するかどうか
Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.
> yes



requireを解決するためにkarma.conf.jsを編集する


そのままテストを実行すると、ブラウザが「const hoge = require('Hoge');」のようなrequire部分が解決できず「ReferenceError: require is not defined」というエラーになってしまう。

そのため、browserifyを使って依存関係を解消する。
// karma.conf.js
module.exports = function(config) {
  config.set({
    // 略

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: [
      'mocha',
      'browserify'
    ],

    // 略

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
      'test/**/*.js': ['browserify']
    },

    // 略
  })
}

frameworksにbrowserifyを追加、そしてpreprocessorsにもbrowserifyを追加することで、コードを1つにまとめてからテストを実行してくれるようになる。



コードを書く


テスト対象のコードを書く

本来はテストファーストというけど、実際やってみるとインターフェースも決まってないのにテストが書けるかー!!となるので、先にテスト対象のコード(ライブラリとか)を書く。
※ この辺の順序は好きなようにお願いします
// ./src/app.js
function add (a, b) {
    return a + b;
}

module.exports = add;

ものすごーく単純な、2つの引数を足して返してくれるだけのfunctionだ。


テストコードを書く

次に実行するテストコードを書く。
// ./test/spec.js
const expect = require('chai').expect;
const add = require('../src/app');

describe('test', () => {
    it('test-it', () => {
        const val = add(1, 2);
        expect(val).to.be.eq(3);
    });
});

今回、テストコードは./src/**/*.jsのディレクトリに入れているが、もちろん場所を変えることもできる。その場合は、karma.conf.jsのfilesを編集する。



Karmaを実行する


karma startコマンドでテストが実行される。
$ karma start
karma start
12 05 2017 09:44:19.374:INFO [framework.browserify]: registering rebuild (autoWatch=true)
12 05 2017 09:44:20.498:INFO [framework.browserify]: 210331 bytes written (0.35 seconds)
12 05 2017 09:44:20.500:INFO [framework.browserify]: bundle built
12 05 2017 09:44:20.501:WARN [karma]: No captured browser, open http://localhost:9876/
12 05 2017 09:44:20.509:WARN [karma]: Port 9876 in use
12 05 2017 09:44:20.510:INFO [karma]: Karma v1.7.0 server started at http://0.0.0.0:9877/
12 05 2017 09:44:20.510:INFO [launcher]: Launching browsers Chrome, Firefox with unlimited concurrency
12 05 2017 09:44:20.527:INFO [launcher]: Starting browser Chrome
12 05 2017 09:44:20.534:INFO [launcher]: Starting browser Firefox
12 05 2017 09:44:22.473:INFO [Chrome 58.0.3029 (Mac OS X 10.10.5)]: Connected on socket 65LffveIFo0LZeLpAAAA with id 47175820
12 05 2017 09:44:23.499:INFO [Firefox 45.0.0 (Mac OS X 10.10.0)]: Connected on socket -UeHEpZpavbkm5rsAAAB with id 19560930
Chrome 58.0.3029 (Mac OS X 10.10.5): Executed 1 of 1 SUCCESS (0.013 secs / 0.001 secs)
Firefox 45.0.0 (Mac OS X 10.10.0): Executed 1 of 1 SUCCESS (0.004 secs / 0.001 secs)
TOTAL: 2 SUCCESS

今回はChromeとFirefoxでテストするように設定しているので、karma startを実行すると2つのブラウザが立ち上がる。終了させる場合は、ターミナルでCtrl+C。

以降、ファイルの変更をwatchして自動でテストを実行してくれる。
テストは1度だけでよい場合は、テスト実行時に「karma start --single-run」というオプションをつけることでwatchせずに終了してくれる。
もしくは、karma.conf.jsのsingleRunをtrueに変えることでも同様のことができる。



おまけ: npm runでテストできるようにする


// package.json
{
  "name": "node-browser-test",
  "version": "1.0.0",
  "main": "./src/app.js",
  "scripts": {
    "test_node": "node_modules/mocha/bin/mocha",
    "test_browser": "karma start",
    "test": "node_modules/mocha/bin/mocha; karma start;"
  },
  "devDependencies": {
    "browserify": "^14.3.0",
    "chai": "^3.5.0",
    "karma": "^1.7.0",
    "karma-browserify": "^5.1.1",
    "karma-chrome-launcher": "^2.1.1",
    "karma-firefox-launcher": "^1.0.1",
    "karma-mocha": "^1.3.0",
    "mocha": "^3.3.0",
    "watchify": "^3.9.0"
  }
}

scriptsにtest_node、test_browser、testを追加している。
mochaはグローバル環境にインストールしていないので、node_modulesから直接実行している。

# Node.js用のテスト
$ npm run test_node

# ブラウザ用のテスト
$ npm run test_browser

# 両方
$ npm run test



参考サイト





以上

written by @bc_rikko

0 件のコメント :

コメントを投稿