Итак, есть опция macro @Tsyvarev, которая была первоначально предложена здесь здесь :
# overwrite install() command with a dummy macro that is a nop
macro (install)
endmacro ()
# configure build system for external libraries
add_subdirectory(external)
# replace install macro by one which simply invokes the CMake
install() function with the given arguments
macro (install)
_install(${ARGV})
endmacro(install)
Примечание ${ARGV}
и ${ARGN}
совпадают, но документы в настоящее время предложите использовать ${ARGN}
. Также тот факт, что макро-переписывание добавляет _
к исходному имени макроса, не документируется, но это по-прежнему поведение. См. Код здесь .
Однако , я никогда не получил вышеуказанный код для правильной работы. Действительно, действительно странные вещи и часто называет install()
дважды.
Альтернатива - также недокументированная - использовать EXCLUDE_FROM_ALL
:
add_subdirectory(external EXCLUDE_FROM_ALL)
Согласно некоторым комментариям, которые я нашел где-то, это отключает install()
для этого подкаталога. Я думаю, что он действительно делает EXCLUDE_FROM_ALL
по умолчанию для всех команд install()
, которые также, вероятно, делают то, что вы хотите. Я действительно не тестировал его, но стоит того.
Измените свой объект ответа:
var response = {
viewName: ""
, data : {}
, render: function(view, viewData) {
this.viewName = view;
this.data = viewData;
}
};
И он будет работать.
Я пришел к выводу, что единственным способом действительно модульных тестовых экспресс-приложений является поддержание большого разделения между обработчиками запросов и вашей основной логикой.
Таким образом, ваша логика приложения должна быть в отдельных модулях, которые могут быть require
d и проверены модулем, и имеют минимальную зависимость от классов Express Request и Response как таковых.
Затем в обработчиках запросов вам нужно вызвать соответствующие методы вашей основной логики классы.
Я приведу пример, как только закончу реструктуризацию моего текущего приложения!
Я думаю, что-то вроде this? (Не стесняйтесь fork the gist или comment, я все еще изучаю это).
Изменить
Вот крошечный пример, встроенный. См. gist для более подробного примера.
/// usercontroller.js
var UserController = {
_database: null,
setDatabase: function(db) { this._database = db; },
findUserByEmail: function(email, callback) {
this._database.collection('usercollection').findOne({ email: email }, callback);
}
};
module.exports = UserController;
/// routes.js
/* GET user by email */
router.get('/:email', function(req, res) {
var UserController = require('./usercontroller');
UserController.setDB(databaseHandleFromSomewhere);
UserController.findUserByEmail(req.params.email, function(err, result) {
if (err) throw err;
res.json(result);
});
});
Чтобы выполнить модульное тестирование вместо тестирования интеграции, я высмеивал объект ответа обработчика запроса.
/* app.js */
import endpointHandler from './endpointHandler';
// ...
app.post('/endpoint', endpointHandler);
// ...
/* endpointHandler.js */
const endpointHandler = (req, res) => {
try {
const { username, location } = req.body;
if (!(username && location)) {
throw ({ status: 400, message: 'Missing parameters' });
}
res.status(200).json({
location,
user,
message: 'Thanks for sharing your location with me.',
});
} catch (error) {
console.error(error);
res.status(error.status).send(error.message);
}
};
export default endpointHandler;
/* response.mock.js */
import { EventEmitter } from 'events';
class Response extends EventEmitter {
private resStatus;
json(response, status) {
this.send(response, status);
}
send(response, status) {
this.emit('response', {
response,
status: this.resStatus || status,
});
}
status(status) {
this.resStatus = status;
return this;
}
}
export default Response;
/* endpointHandler.test.js */
import Response from './response.mock';
import endpointHandler from './endpointHander';
describe('endpoint handler test suite', () => {
it('should fail on empty body', (done) => {
const res = new Response();
res.on('response', (response) => {
expect(response.status).toBe(400);
done();
});
endpointHandler({ body: {} }, res);
});
});
Затем, чтобы достичь интеграционного тестирования, вы можете высмеять свой endpointHandler и вызвать конечную точку с помощью Supertest .
Мне тоже было интересно, но специально для модульных тестов, а не для интеграционных тестов. Это то, что я делаю прямо сейчас,
test('/api base path', function onTest(t) {
t.plan(1);
var path = routerObj.path;
t.equals(path, '/api');
});
test('Subrouters loaded', function onTest(t) {
t.plan(1);
var router = routerObj.router;
t.equals(router.stack.length, 5);
});
Где routerObj - это просто {router: expressRouter, path: '/api'}
. Затем я загружаю в подпрограммы с помощью var loginRouterInfo = require('./login')(express.Router({mergeParams: true}));
, а затем экспресс-приложение вызывает функцию init, принимающую в экспресс-маршрутизаторе параметр. Затем initRouter вызывает router.use(loginRouterInfo.path, loginRouterInfo.router);
для монтирования подпроцессора.
Подпроцессор может быть протестирован с помощью:
var test = require('tape');
var routerInit = require('../login');
var express = require('express');
var routerObj = routerInit(express.Router());
test('/login base path', function onTest(t) {
t.plan(1);
var path = routerObj.path;
t.equals(path, '/login');
});
test('GET /', function onTest(t) {
t.plan(2);
var route = routerObj.router.stack[0].route;
var routeGetMethod = route.methods.get;
t.equals(routeGetMethod, true);
var routePath = route.path;
t.equals(routePath, '/');
});
Самый простой способ проверить HTTP с помощью выражения - это украсть HTTP-помощник TJ
I лично использовать свой помощник
it("should do something", function (done) {
request(app())
.get('/session/new')
.expect('GET', done)
})
Если вы хотите специально протестировать свой объект маршрута, то выполните правильные mocks
describe("Default Route", function(){
it("should provide the a title and the index view name", function(done){
routes.index({}, {
render: function (viewName) {
viewName.should.equal("index")
done()
}
})
})
})
Как было рекомендовано в комментариях другими, похоже, канонический способ тестирования контроллеров Express через supertest .
Примерный пример может выглядеть так:
describe('GET /users', function(){
it('respond with json', function(done){
request(app)
.get('/users')
.set('Accept', 'application/json')
.expect(200)
.end(function(err, res){
if (err) return done(err);
done()
});
})
});
Потенциал: вы можете протестировать весь свой стек за один раз.
Даунсайд: он чувствует и действует как тестирование интеграции.
integration
, и, возможно, маршруты тестирования должны быть оставлены на интеграционных тестах. Я имею в виду, что функциональность маршрутов, соответствующих их определенным обратным вызовам, предположительно уже проверена express.js; любая внутренняя логика для получения конечного результата маршрута, в идеале должна быть модульной вне его, и эти модули должны быть проверены на единицу. Их взаимодействие, т. Е. Маршрут, должно быть проверено на интеграцию. Согласитесь?
– Aditya M P
6 March 2017 в 13:33
, если модульное тестирование с экспресс-4 отмечает этот пример из gjohnson :
var express = require('express');
var request = require('supertest');
var app = express();
var router = express.Router();
router.get('/user', function(req, res){
res.send(200, { name: 'tobi' });
});
app.use(router);
request(app)
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '15')
.expect(200)
.end(function(err, res){
if (err) throw err;
});