概要
jQueryのajaxを使ったコードのユニットテストするために、
今回はSinon.JSのスタブを使って、リモートのAPIを叩かずにテストします。
本記事では、直接jQueryの$.get
, $.ajax
を叩いて、
そのcallback内でassertしてますが、
実際のプロジェクトなど、
テスト対象の関数内で$.get
, $.ajax
を使ってる場合にも応用できると思います。
Sinon.JSのFake XHRやFake serverを使う方法がネット上にたくさんありますが、
どうもうまくいかなかったのでsinon.stubを利用しました。
20170626 update
その後うまくいく方法が見つかったので別途、投稿しました。
Mocha+Sinon.JSでjQueryのajaxコールを、XMLHttpRequestを置き換えてテストする。 - Qiita
環境
macOS Sierra 10.12.5
Docker for Mac 17.03.1-ce-mac12 (17661)
準備
ローカルの環境を汚さずに済むように、Docker上で環境構築します。
こちらにDockerfile
からテストコードまで入ったプロジェクトを上げておきましたので、git clone
して使ってみてください。
環境構築
git cloneしてdocker buildします
$ git clone https://github.com/teruchi/mocha-sinon.git
$ cd mocha-sinon
$ ./docker.sh build
テスト実行!
docker.sh
の中にdockerコンテナ内でmochaを起動するスクリプトを入れておいたので、それを使います。
$ ./docker.sh mocha
どうでしょう?
こんな感じのメッセージが出力されれば成功です。
Test User API
✓ get /api/users/100
✓ ajax /api/users/100
2 passing (24ms)
解説
Dockerコンテナ内の環境について
Dockerfile
まずDockerfileの説明をします。
FROM centos:7 【1】
# Install CentOS GPG Key
RUN rpm --import http://vault.centos.org/RPM-GPG-KEY-CentOS-7
# Install EPEL
RUN rpm --import http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7 && \
yum install -y epel-release && \
yum update -y && \
yum clean all
RUN yum install -y --enablerepo=epel \ 【2】
nodejs npm && \
yum clean all
# Javascript Test Suite
RUN npm -g install mocha chai sinon jsdom jquery 【3】
ENV NODE_PATH /usr/lib/node_modules 【4】
# Runtime Setting
WORKDIR /opt 【5】
CentOS 7上に構築しています。 【1】
yum
でnodejs
とnpm
をインストールした上で、 【2】
npm
でmocha
、chai
、sinon
、jsdom
、jquery
をインストールしています。 【3】
jsdom
を入れないと、ブラウザレスでjQueryを使うことができないので必要でした。
NODE_PATH
を指定することで、npm -g
でインストールしたパッケージも読みに行くことができるようです。 【4】
docker run
した時にテストコードなどが入っているディレクトリでmocha
コマンドがすぐ使えるようにWORKDIR
をしてしてます。
docker.sh
docker build
とdocker run
でmochaを実行するbashスクリプトの説明をします。
#
# Dockerfile
#
REPO="teruchi/mocha-sinon" 【1】
TAG="latest"
DOCKERFILE="Dockerfile"
SERVICE_NAME="mocha-sinon"
case "$1" in
"build" ) 【2】
docker build \
-t ${REPO}:${TAG} \
-f ${DOCKERFILE} \
.
exit
;;
"mocha" ) 【3】
docker run \
--rm \
--name ${SERVICE_NAME} \
-v "$(pwd)"/opt:/opt \
${REPO}:${TAG} \
mocha
exit
;;
*)
echo "usage: docker.sh [build|mocha]"
;;
esac
私の方で利用しているDocker repositoryのパスです。【1】
ご利用の環境に合わせて変更してください。
docker build
してます。【2】
dockerのvolume mountを使って、ホストのoptディレクトリを、
コンテナ内の/opt
にマウントすることで、
テストコードを修正しつつ、scpなど使わずにコンテナ内でテストを即実行します。【3】
テストコード
最後になってしまいましたが、テストコードです。
// Sinon.JS初期化
var sinon = require('sinon');
var assert = require('assert');
// jQuery初期化
var jsdom = require('jsdom/lib/old-api.js');
var window = jsdom.jsdom().defaultView;
var $ = require('jquery')(window);
/**
* User APIのテスト
*/
describe('Test User API', function () {
/**
* $.getのテスト
* ※callbackの完了を待つ
*/
it("get /api/users/100", function (done) {
// sinon.stab で$.getを置き換え
sinon.stub($, 'get').callsFake(function(url, success, dataType) {
success({
id: 100,
name: 'teruchi'
});
});
// テスト
$.get(
'/api/users/100',
function (data) {
// Assertion
assert.equal(100, data.id);
assert.equal('teruchi', data.name);
// スタブから元に戻す
$.get.restore();
// callback完了をmochaに通知
done();
},
'json'
);
});
/**
* $.ajaxのテスト
* ※callbackの完了を待つ
*/
it("ajax /api/users/100", function (done) {
// sinon.stab で$.ajaxのreturnのdoneを置き換え
sinon.stub($, 'ajax').returns({
done : function(callback) {
callback({
id: 100,
name: 'teruchi'
});
}
});
// テスト
$.ajax({
method: 'GET',
url: '/api/users/100',
dataType: 'json'
})
.done(function(data) {
// Assertion
assert.equal(100, data.id);
assert.equal('teruchi', data.name);
// スタブから元に戻す
$.ajax.restore();
// callback完了をmochaに通知
done();
});
});
});
コメントに書いてある通りですが、ポイントとしては、
- jsdomを使うことでPhantom.jsなどを使わずにjQueryのテストをする
- itのパラメーター(
done
)付きを使うことでcallbackを待つ -
sinon.stab()
でjQueryのメソッドを置き換える
のあたりかと思います。