Node and Expressを初めて使用し、ルート/コントローラーを単体テストしようとしています。ルートをコントローラーから分離しました。どのようにルートをテストしますか?
config/express.js
var app = express();
// middleware, etc
var router = require('../app/router')(app);
app/router/index.js
module.exports = function(app) {
app.use('/api/books', require('./routes/books'));
};
app/router/routes/books.js
var controller = require('../../api/controllers/books');
var express = require('express');
var router = express.Router();
router.get('/', controller.index);
module.exports = router;
app/api/controllers/books.js
// this is just an example controller
exports.index = function(req, res) {
return res.status(200).json('ok');
};
app/tests/api/routes/books.test.js
var chai = require('chai');
var should = chai.should();
var sinon = require('sinon');
describe('BookRoute', function() {
});
コード:
config/express.js
var app = express();
// middleware, etc
var router = require('../app/router')(app);
module.exports = app;
app/tests/api/routes/books.test.js
var chai = require('chai');
var should = chai.should();
var sinon = require('sinon');
var request = require('supertest');
var app = require('config/express');
describe('BookRoute', function() {
request(app)
.get('/api/books')
.expect('Content-Type', /json/)
.expect('Content-Length', '4')
.expect(200, "ok")
.end(function(err, res){
if (err) throw err;
});
});
考慮事項:
サーバーが一連のテストの開始時に初期状態を必要とする場合(サーバーの状態を変更する呼び出しを実行しているため)、新しく構成されたアプリと各グループの先頭を返す関数を記述する必要がありますテスト。 NPMライブラリがあります: https://github.com/bahmutov/really-need これにより、サーバーの新たにインスタンス化されたバージョンが必要になります。
ルーターからコントローラーを分離しているため、これは興味深いことです。コメントで言及されている他のStackOverflowの記事は、コントローラーをテストする良い方法だと思います。単体テストで留意すべきことは、正確にテストすることです。おそらく独自の単体テストがあるため、エクスプレスライブラリをテストするためのテストを作成する必要はありません。したがって、ライブラリへの呼び出しをテストするだけです。したがって、書籍のルートでは、次の1行のコードをテストするだけです。
router.get('/', controller.index);
エクスプレスライブラリからルートのリストを取得する明らかな方法があるかどうかを確認するために周りを見回しましたが、表示されませんでした。おそらくライブラリ自体を見て、内部をチェックして、ルートを正しく設定しているかどうかを確認することができます。ただし、別のオプションは、それをモックアップし、正しく呼び出していることを確認することです。
この1行のコードをテストするには、Javascriptの基本的な部分をモックアップする必要があるため、これはかなり複雑になります。以下がその方法です。
describe('BookRoute', function() {
it("should route / to books controller index", function() {
var controller = require('../../../api/controllers/books');
var orig_this = this;
var orig_load = require('module')._load;
var router = jasmine.createSpyObj('Router', ['get']);
var express = jasmine.createSpyObj('express', ['Router']);
express.Router.and.returnValues(router);
spyOn(require('module'), '_load').and.callFake(function() {
if (arguments[0] == 'express') {
return express;
} else {
return orig_load.apply(orig_this, arguments);
}
});
require("../../../router/routes/books");
expect(router.get).toHaveBeenCalledWith('/', controller.index);
});
});
ここで起こっているのは、JasmineのspyOn関数を使用して、すべてのrequire呼び出しを処理するmodule.jsの_load関数をspyOnすることです。これは、booksルーターが必要なときにrequire( 'express')を呼び出すと、jasmine.createSpyObjで作成したエクスプレスSpyObjを返すことができるようにするためです。 expressをspyオブジェクトに置き換えたら、Router SpyObjを返すことができ、これによりrouter.getをスパイできます。次に、「/」とcontroller.indexで呼び出されることを確認します。
これを多用したい場合、おそらく何らかのユーティリティにすることができます。
私は通常、よりオブジェクト指向のアプローチを使用することでこのことの多くを回避し、テスト用にモックできるオブジェクトをどこでも渡すか、Angular =使用します。