Как программно закрыть экземпляр ExpressJS для тестирования?

109

Я пытаюсь понять, как закрыть экземпляр Express. В принципе, мне нужен обратный .listen(port)вызов - как заставить сервер Express ОСТАНОВИТЬ прослушивание, освободить порт и аккуратно завершить работу?

Я знаю, что это может показаться странным вопросом, так что вот контекст; может быть, есть другой способ подойти к этому, и я ошибаюсь в этом. Я пытаюсь настроить среду тестирования для своего приложения socket.io/nodejs. Это одностраничное приложение, поэтому в моих сценариях тестирования (я использую Mocha, но на самом деле это не имеет значения) Я хочу иметь возможность запускать сервер, запускать тесты, а затем выключать сервер. Я могу обойти это, предположив, что либо сервер включен до начала теста, либо если один из тестов запускает сервер и каждый последующий тест предполагает, что он работает, но это действительно беспорядочно. Я бы предпочел, чтобы каждый тестовый файл запускал экземпляр сервера с соответствующими настройками, а затем выключал этот экземпляр после завершения тестов. Это означает, что при запуске теста нет никаких странных зависимостей, и все чисто. Это также означает, что я могу проводить тестирование при запуске / завершении работы.

Итак, какие-нибудь советы о том, как это сделать? Я думал о ручном запуске исключений, чтобы его отключить, но это кажется беспорядочным. Я просмотрел документы и исходный код Express, но, похоже, не могу найти никакого метода, который отключит сервер. Для этого также может быть что-то в socket.io, но поскольку сервер сокетов просто подключен к серверу Express, я думаю, что это должно происходить на уровне express.

нарисовал
источник

Ответы:

158

Ситуация изменилась, потому что экспресс-сервер больше не наследует HTTP-сервер узла. К счастью, app.listen возвращает экземпляр сервера.

var server = app.listen(3000);

// listen for an event
var handler = function() {
  server.close();
};
Рич Аподака
источник
23
В случае тестирования Mocha, когда вам требуется ('приложение'), я расширяю его до объекта приложения: app.server = app.listen (3000); так что позже я могу сказать: var app = require ('./ app'); app.server.close ();
Джек Чи
2
при тестировании сервера зайдите на github.com/visionmedia/supertest, он позволит вам протестировать без запуска реального сервера
Лукас Лисис, 01
Я также предлагаю вам передать обратный вызов done, server.close()если вы вызываете его из хука.
Уллаури
1
Примечание. Существует большая разница между app, который является экземпляром Express Application, и возвращаемым значением app.listen, который является базовым экземпляром собственного HTTP-сервера, который имеет метод close. @JackChi намекнул на это выше.
ajxs
Не вызывает ли это проблем с открытыми клиентскими сокетами, которые остались открытыми?
Кэмерон Тэклинд
20

Используйте app.close(). Полный пример:

var app = require('express').createServer();
app.get('/', function(req, res){
  res.send('hello world');
});
app.get('/quit', function(req,res) {
  res.send('closing..');
  app.close();
});
app.listen(3000);

Вызовите app.close()внутри обратного вызова после завершения тестов. Но помните, что процесс все еще выполняется (хотя он больше не слушает).

Если после этого вам нужно завершить процесс, то звоните process.exit(0).

Ссылки:

app.close: http://nodejs.org/docs/latest/api/http.html#server.close (то же самое касается)

process.exit: http://nodejs.org/docs/latest/api/process.html#process.exit

Шриджан Чоудхари
источник
1
Идеально, именно то, что я искал. Думаю, я не нашел его в Express, потому что они расширяли HTTP-сервер основного узла, чего я не совсем понимал. Спасибо!
drewww
Спасибо, Шриджан, мне это тоже помогло
Адам Хопкинсон
Это все еще правда? express.createServer помечается как устаревший и выдает ошибку о том, что приложение больше не наследуется от сервера
http.js
4
Это не действует, так как экспресс 3.
gprasant
4
Показывать URL-адрес для закрытия такого сервера - это не очень хорошая идея. ИМХО.
shime
2

Я много раз отвечал на вопрос «как завершить работу HTTP-сервера» на разных каналы поддержки. К сожалению, я не могу рекомендовать какой - либо из существующих библиотек , поскольку они отсутствуют в том или ином пути. С тех пор я собрал пакет, который (как мне кажется) обрабатывает все случаи, ожидаемые от корректного завершения работы HTTP-сервера.

https://github.com/gajus/http-terminator

Основное преимущество http-terminator заключается в том, что:

  • это не обезьяна-патч Node.js API
  • он немедленно уничтожает все сокеты без прикрепленного HTTP-запроса
  • он позволяет плавно отключать сокеты с текущими HTTP-запросами
  • он правильно обрабатывает HTTPS-соединения
  • он сообщает соединениям, использующим keep-alive, что сервер выключается, устанавливая заголовок connection: close
  • он не завершает процесс Node.js

Использование с Express.js:

import express from 'express';
import {
  createHttpTerminator,
} from 'http-terminator';

const app = express();

const server = app.listen();

const httpTerminator = createHttpTerminator({
  server,
});

await httpTerminator.terminate();
Gajus
источник
0
//... some stuff 

var server = app.listen(3000);
server.close();
алекс дикый
источник
-1

Вы можете легко сделать это, написав сценарий bash для запуска сервера, запуска тестов и остановки сервера. Это имеет то преимущество, что вы можете использовать псевдоним для этого сценария для быстрого и легкого выполнения всех ваших тестов.

Я использую такие сценарии для всего процесса непрерывного развертывания. Вам следует взглянуть на Dead Simple Git Workflow Джона Рохана, чтобы получить некоторое представление об этом.

Джош Смит
источник
2
Это сработает, но я бы предпочел, если возможно, решение без bash. Возможно, это глупое предпочтение, но я бы хотел запускать / останавливать сервер из тестового контекста, потому что это упрощает написание тестов, специфичных для конфигурации сервера + тесты запуска / выключения. Кроме того, он не подразумевает косвенного выполнения тестов, связанных с сервером, через отдельный сценарий.
drewww
Почему вы пишете тесты для среды? Возможно, я ошибаюсь, но это кажется мне плохой практикой. Я бы попытался не зависеть от среды при тестировании, поскольку вы хотите, чтобы тесты работали в вашей команде независимо от среды разработки.
Джош Смит
Я не думаю, что здесь ничего специфичного для окружающей среды. Будет несколько различных вариантов запуска для сервера (например, чтение параметров конфигурации из файла, состояние загрузки из хранилища данных и т. Д.), Которые было бы неплохо протестировать в той же среде, что и все остальное. Я также хотел бы иметь тесты, которые, например, отключают сервер, снова запускают его и проверяют, не потеряли ли он состояние в процессе. Это проще, если я могу делать это программно из узла, чем тестировать код в bash.
drewww
Вы бы не поместили свой тестовый код в сам bash. Вы просто запускаете сервер и запускаете тесты из сценария так же, как вы делаете это сами в командной строке. Там нет особой магии.
Джош Смит