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.