Как unit test выразить маршруты маршрутизатора
Я новичок в Node и Express, и я пытаюсь unit test мои маршруты/контроллеры. Я отделил свои маршруты от своих контроллеров. Как мне пройти тестирование моих маршрутов?
конфигурации /express.js
var app = express();
// middleware, etc
var router = require('../app/router')(app);
приложение/маршрутизатор/index.js
module.exports = function(app) {
app.use('/api/books', require('./routes/books'));
};
приложение/маршрутизатор/маршруты/books.js
var controller = require('../../api/controllers/books');
var express = require('express');
var router = express.Router();
router.get('/', controller.index);
module.exports = router;
приложение/API/контроллеры/books.js
// this is just an example controller
exports.index = function(req, res) {
return res.status(200).json('ok');
};
приложение/тесты/API/маршруты/books.test.js
var chai = require('chai');
var should = chai.should();
var sinon = require('sinon');
describe('BookRoute', function() {
});
Ответы
Ответ 1
код:
конфигурации /express.js
var app = express();
// middleware, etc
var router = require('../app/router')(app);
module.exports = app;
приложение/тесты/API/маршруты/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, которая позволит вам потребовать только что обновленную версию вашего сервера.
Ответ 2
Я нашел этот блог невероятно проницательным при тестировании своих собственных конечных серверов.
В блоге он адресует:
-
Как использовать библиотеку тестирования конечных точек supertest.
-
Как программно разворачивать и сбрасывать экспресс-сервер с помощью необходимых маршрутов до и после каждого теста конечной точки. (он также объясняет, почему вы хотели бы это сделать).
-
Как избежать общей ошибки, требуйте кэширования ваших модулей, необходимых в ваших модульных тестах, что приведет к непредвиденным последствиям.
Надеюсь, это поможет. Удачи, и если у вас есть дополнительные вопросы, дайте мне знать.
Ответ 3
Это интересно, потому что вы отключили свои контроллеры от своих маршрутизаторов. Другая статья StackOverflow, упомянутая в комментариях, является хорошим способом протестировать ваши контроллеры, я думаю. То, что нужно помнить с модульными тестами, - это то, что вы точно тестируете. Вам не нужно писать тесты для тестирования экспресс-библиотеки, потому что, по-видимому, у нее есть свои собственные модульные тесты. Поэтому вам просто нужно проверить свои звонки в библиотеку. Итак, для маршрута книг вам просто нужно проверить эту строку кода:
router.get('/', controller.index);
Я осмотрелся, чтобы узнать, есть ли очевидный способ получить список маршрутов из экспресс-библиотеки, но я его не видел. Возможно, вы можете просто взглянуть на библиотеку и проверить ее внутренности, чтобы убедиться, что вы правильно настроили маршрут. Другой вариант, однако, состоит в том, чтобы высмеять его и просто проверить, правильно ли вы его вызываете.
Это будет довольно сложно, потому что вам нужно макетировать некоторые фундаментальные части 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 для spyOn функции _load в module.js, которая является тем, что обрабатывает все требуемые вызовы. Это так, что, когда нам нужен роутер книг и требует его ( "экспресс" ), мы можем вернуть наш экспресс SpyObj, который мы создали с помощью jasmine.createSpyObj. После того, как мы заменили express нашим объектом-шпионом, мы можем вернуть его Router SpyObj, который позволит нам шпионить за router.get. Затем мы можем проверить, чтобы он был вызван с помощью '/' и controller.index.
Возможно, это может быть сделано в какую-то утилиту, если вы хотите использовать это много.
Я обычно избегаю многого этого, используя более объектно-ориентированный подход, и либо я обхожу вокруг какого-то объекта во всем мире, что я могу издеваться над тестами, или вы можете использовать какую-то инъекцию зависимости, например, Angular.