Jak programowo zamknąć wystąpienie ExpressJS w celu przetestowania?


106

Próbuję dowiedzieć się, jak wyłączyć wystąpienie Express. Zasadniczo chcę mieć odwrotność .listen(port)połączenia - jak sprawić, aby serwer Express ZATRZYMAŁ nasłuchiwanie, zwolnił port i zamknął czysto?

Wiem, że może to być dziwne zapytanie, więc oto kontekst; może jest inny sposób podejścia do tego i myślę o tym w niewłaściwy sposób. Próbuję skonfigurować środowisko testowe dla mojej aplikacji socket.io/nodejs. Jest to aplikacja jednostronicowa, więc w moich skryptach testowych (używam Mocha, ale to nie ma znaczenia) Chcę móc uruchomić serwer, przeprowadzić testy, a następnie wyłączyć serwer. Mogę obejść ten problem, zakładając, że albo serwer jest włączony przed rozpoczęciem testu, albo przez jeden z testów uruchamiający serwer i każdy kolejny test zakłada, że ​​jest włączony, ale to naprawdę bałagan. Zdecydowanie wolałbym, aby każdy plik testowy uruchamiał instancję serwera z odpowiednimi ustawieniami, a następnie zamykał ją po zakończeniu testów. Oznacza to, że nie ma żadnych dziwnych zależności od uruchomienia testu i wszystko jest czyste. Oznacza to również, że mogę przeprowadzić testy uruchamiania / zamykania.

Masz jakąś radę, jak to zrobić? Myślałem o ręcznym uruchamianiu wyjątków, aby go wyłączyć, ale wydaje się to kłopotliwe. Przeszukałem dokumenty i źródła Express, ale nie mogę znaleźć żadnej metody, która wyłączyłaby serwer. Może być coś do tego w socket.io, ale ponieważ serwer gniazd jest właśnie podłączony do serwera Express, myślę, że musi to się wydarzyć w warstwie ekspresowej.

Odpowiedzi:


156

Sytuacja się zmieniła, ponieważ serwer ekspresowy nie dziedziczy już po serwerze HTTP węzła. Na szczęście app.listen zwraca instancję serwera.

var server = app.listen(3000);

// listen for an event
var handler = function() {
  server.close();
};

23
W przypadku testów Mocha, które wymagają ('app'), rozszerzam na obiekt aplikacji: app.server = app.listen (3000); więc później mogę powiedzieć: var app = require ('./ app'); app.server.close ();
Jack Chi,

2
podczas testowania serwera odwiedź github.com/visionmedia/supertest , pozwoli ci to przetestować bez uruchamiania rzeczywistego serwera
Lukas Liesis

Sugerowałbym również przekazanie gotowego wywołania zwrotnego do, server.close()jeśli dzwonisz z poziomu hooka.
Ullauri

Uwaga: istnieje duża różnica między „app”, która jest instancją Express Application, a wartością zwracaną przez „app.listen”, który jest podstawową natywną instancją serwera HTTP, która ma metodę „close”. @JackChi wspomniał o tym powyżej.
ajxs

Czy to nie powoduje problemów z otwartymi gniazdami klienta, które są pozostawione otwarte?
Cameron Tacklind

18

Użyj app.close(). Pełny przykład:

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);

Wywołaj app.close()wewnątrz wywołania zwrotnego po zakończeniu testów. Pamiętaj jednak, że proces nadal działa (chociaż już nie nasłuchuje).

Jeśli po tym musisz zakończyć proces, zadzwoń process.exit(0).

Spinki do mankietów:

app.close: http://nodejs.org/docs/latest/api/http.html#server.close (to samo dotyczy)

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


1
Idealnie, dokładnie to, czego szukałem. Wydaje mi się, że nie znalazłem tego w Express, ponieważ rozszerzali główny serwer http węzła, czego nie do końca rozumiałem. Dzięki!
drewww

Dzięki, Srijan, to też mi pomogło
Adam Hopkinson

Czy to nadal prawda? express.createServer jest oznaczony jako przestarzały i wyświetla błąd informujący, że aplikacja nie dziedziczy już z serwera
http.js

4
To nie jest ważne od czasu ekspresowego 3.
gprasant

4
Ujawnienie adresu URL w celu zamknięcia serwera takiego jak ten nie jest dobrym pomysłem IMHO.
shime

2

Wiele razy odpowiadałem na różne warianty „jak zakończyć działanie serwera HTTP” kanały wsparcia. Niestety nie mogłem polecić żadnej z istniejących bibliotek, ponieważ w jakiś sposób im brakuje . Od tego czasu stworzyłem pakiet, który (jak sądzę) obsługuje wszystkie spodziewane przypadki płynnego zakończenia serwera HTTP.

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

Główną zaletą terminatora http :

  • nie naprawia małpy API Node.js.
  • natychmiast niszczy wszystkie gniazda bez dołączonego żądania HTTP
  • pozwala na bezpieczne przekroczenie limitu czasu do gniazd z trwającymi żądaniami HTTP
  • prawidłowo obsługuje połączenia HTTPS
  • informuje połączenia za pomocą funkcji keep-alive, że serwer jest zamykany, ustawiając nagłówek connection: close
  • nie kończy procesu Node.js.

Użycie z 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();



-1

Możesz to łatwo zrobić, pisząc skrypt bash, aby uruchomić serwer, uruchomić testy i zatrzymać serwer. Ma to tę zaletę, że pozwala na alias do tego skryptu w celu szybkiego i łatwego uruchamiania wszystkich testów.

Używam takich skryptów do całego procesu ciągłego wdrażania. Aby uzyskać więcej informacji na ten temat, należy zapoznać się z przepływem pracy Jona Rohana Dead Simple Git .


2
To zadziała, ale wolałbym rozwiązanie bez bash, jeśli to możliwe. Może to głupia preferencja, ale chciałbym uruchamiać / zatrzymywać serwer z kontekstu testowego, ponieważ ułatwia to pisanie testów specyficznych dla konfiguracji serwera + testów uruchamiania / zamykania. Ponadto nie wprowadza konieczności uruchamiania testów związanych z serwerem za pomocą oddzielnego skryptu.
drewww

Dlaczego piszesz testy specyficzne dla środowiska? Może się mylę, ale wydaje mi się to złą praktyką. Postarałbym się pozostać agnostykiem środowiskowym podczas testowania, ponieważ chciałbyś, aby testy działały w całym zespole, niezależnie od środowiska programistycznego.
Josh Smith

Nie robię tu nic specyficznego dla środowiska, nie sądzę. Będzie kilka różnych opcji uruchamiania serwera (takich jak odczyt opcji konfiguracyjnych z pliku, ładowanie stanu z magazynu danych itp.), Które byłoby fajnie przetestować w tej samej strukturze, w której testuję wszystko inne. Chciałbym również przeprowadzić testy, które na przykład zamkną serwer, przywróć go ponownie i upewnij się, że nie stracił stanu w trakcie. To łatwiejsze, jeśli mogę to zrobić programowo z węzła, niż testowanie kodu również w bashu.
drewww

Nie umieściłbyś kodu testowego w samym bashu. Po prostu uruchomisz serwer i uruchomisz testy ze skryptu, tak jak zrobiłbyś to sam w linii poleceń. Nie ma tam żadnej specjalnej magii.
Josh Smith
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.