たまにしか書かない JavaScript でもちゃんとテストを書く習慣を身につけたいと思い、 Grunt で Jasmine によるテスト実行環境を作ってみた。
grunt-contrib-jasmine
を使う。
gruntjs/grunt-contrib-jasmine
https://github.com/gruntjs/grunt-contrib-jasmine
準備
プロジェクト用のディレクトリを作成して grunt とプラグインをインストール。
% mkdir -p jasmine-test/{src/js,spec} && cd jasmine-test
% npm init
% npm install grunt grunt-contrib-jasmine --save-dev
これでディレクトリ構造は以下のようになる。
jasmine-test
├── node_modules
│ ├── grunt
│ └── grunt-contrib-jasmine
├── package.json
├── spec
└── src
└── js
JavaScript のテスト
テスト対象の javascript ファイルを作成する。
var Foo = (function() {
function Foo() {}
Foo.prototype.name = function() {
return 'Foo';
};
return Foo;
})();
対応する spec ファイルを作成。
describe('Foo', function() {
var foo;
beforeEach(function() {
foo = new Foo();
});
it('should return name', function (){
expect(foo.name()).toEqual('Foo');
});
});
Gruntfile.js を作成。
% vim Gruntfile.js
内容は以下のようにした。
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
jasmine: {
all: {
src: 'src/js/**/*.js',
options: {
specs: 'spec/**/*.spec.js',
},
},
},
});
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.registerTask('default', ['jasmine']);
};
実行してみる。
% grunt
Running "jasmine:all" (jasmine) task
Testing jasmine specs via PhantomJS
Foo
✓ should return name
1 spec in 0.002s.
>> 0 failures
Done, without errors.
上手く動いてるっぽい。
試しに返す文字列を変更して再度実行。
% grunt
Running "jasmine:all" (jasmine) task
Testing jasmine specs via PhantomJS
Foo
X should return name
Expected 'Bar' to equal 'Foo'. (1)
1 spec in 0.003s.
>> 1 failures
Warning: Task "jasmine:all" failed. Use --force to continue.
Aborted due to warnings.
ちゃんとエラーになった。
CoffeeScript のテスト
次は CoffeeScript に対しても spec を実行できるようにしてみる。
直接 coffee に対して spec を実行する方法もありそうだけど、軽く調べた感じでは見つけられなかったので、一旦 js に変換してから spec が実行されるようにした。
先ほどのプロジェクトディレクトリ下に追加で CoffeeScript 用のディレクトリを作成し、 grunt-contrib-coffee
をインストール。
% mkdir src/coffee
% npm install grunt-contrib-coffee --save-dev
これでディレクトリ構造は以下のようになる。
jasmine-test
├── Gruntfile.js
├── node_modules
│ ├── grunt
│ ├── grunt-contrib-coffee
│ └── grunt-contrib-jasmine
├── package.json
├── spec
│ └── foo.spec.js
└── src
├── coffee
└── js
テスト対象の CoffeeScript を作成。
class Bar
name: ->
'Bar'
spec も coffee で書いて変換後に実行、としたいところだが、取り敢えず今回は js で作成。
describe('Bar', function() {
var bar;
beforeEach(function() {
bar = new Bar();
});
it('should return name', function (){
expect(bar.name()).toEqual('Bar');
});
});
Gruntfile.js
を以下のように変更。
coffee
の options
に bare: true
が無いと変換後の js が無名関数で囲まれて spec から参照できなくなるので注意。
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
coffee: {
compile: {
options: {
bare: true,
},
files: [{
expand: true,
cwd: 'src/coffee',
src: ['*.coffee'],
dest: 'src/js/',
ext: '.js',
}]
}
},
jasmine: {
all: {
src: 'src/js/**/*.js',
options: {
specs: 'spec/**/*.spec.js',
},
},
},
});
grunt.loadNpmTasks('grunt-contrib-coffee');
grunt.loadNpmTasks('grunt-contrib-jasmine');
grunt.registerTask('default', ['coffee', 'jasmine']);
};
実行。
% grunt
Running "coffee:compile" (coffee) task
>> 1 files created.
Running "jasmine:all" (jasmine) task
Testing jasmine specs via PhantomJS
Bar
✓ should return name
Foo
✓ should return name
2 specs in 0.005s.
>> 0 failures
Done, without errors.
上手く動いたっぽい。
あとは以前調べた Grunt で複数の CoffeeScript を一つの無名関数内にまとめる あたりと組み合わせて
- coffee でコード、spec を書く
- どちらも js にコンパイルして spec 実行
- アプリケーションコードを一つの js に結合して無名関数で囲む
とかやれば良さそう。
参考
grunt.js - grunt+jasmineな環境作成手順 - Qiita
http://qiita.com/ampersand/items/0811f788accd3651e04a
Jenkins, Grunt, Jasmine で JavaScript のテストを CI - Please Sleep
http://please-sleep.cou929.nu/javascript-ci-with-jasmine-grunt-jenkins.html
coffeescript自動コンパイルでjasmine自動テストなgrunt環境構築 - よしそぶろぐ
http://blog.yoshiso.net/post/63619404740/coffeescript-jasmine-grunt