2012-06-10 13 views
15

Próbuję stworzyć samodzielny zestaw testów używając mocha, który w idealnym świecie uruchomi moją aplikację express.js, użyje zombie do renderowania strony, sprawdzi kilka rzeczy, a następnie odłóż/zabij aplikację express.js.Instalacja/rozkład aplikacji express.js z mocha

Czy istnieje łatwy/najlepszy sposób na zrobienie tego?

NB. Mogę po prostu uruchomić serwer aplikacji ekspresowej przed uruchomieniem testów, ale na szczęście Yaks nie będzie ich golił.

+2

Nicea pytanie.Sam się nad tym zastanawiałem, ale po tygodniu po prostu się poddałem. Zombie naprawdę denerwowało mnie do pracy. Dużo czytam o PhantomJS, ale sam tego nie wypróbowałem. – Pickels

Odpowiedz

23

Najpierw należy przenieść rzeczywistą konfigurację aplikacji do modułu i zaimportować ją do pliku, który faktycznie uruchamia aplikację. Teraz, gdy jest to oddzielne, możesz mieć aplikację w pełnym stanie, zanim zaczniesz słuchać.

Powinieneś przenieść rzeczywistą konfigurację swojej aplikacji do osobnego pliku, nazwijmy ją app.js, możemy wywołać nasłuchiwanie z uruchamianego pliku, nazwijmy go index.js.

Więc app.js wyglądałby następująco:

var express = require('express') 
    , routes = require('./routes'); 

var app = module.exports = express.createServer(); 

// Configuration 

app.configure(function(){ 
    app.set('views', __dirname + '/views'); 
    app.set('view engine', 'jade'); 
    app.use(express.bodyParser()); 
    app.use(express.methodOverride()); 
    app.use(app.router); 
    app.use(express.static(__dirname + '/public')); 
}); 

app.configure('development', function(){ 
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); 
}); 

app.configure('production', function(){ 
    app.use(express.errorHandler()); 
}); 

// Routes 

app.get('/', routes.index); 

i index.js wyglądałby następująco:

var app = require('./app'); 

app.listen(3000, function(){ 
    console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env); 
}); 

ten oddziela ładowanie aplikacji z konieczności rzeczywiście go słuchać, co pozwala na załaduj tę aplikację do testów jednostkowych.

W twoich testach jednostkowych, zrobiłbyś coś w metodzie instalacji i metodzie wynoszenia, aby wywołać i obniżyć serwer.

w teście plik/app_tests.js:

describe('app', function(){ 
    var app = require('../app'); 
    beforeEach(function(){ 
    app.listen(3000); 
    }); 
    // tests here 
    afterEach(function(){ 
    app.close(); 
    }) 
}); 
+0

Awesome! Ale w moim przypadku mam wiele plików testowych i wygląda na to, że mocha wykonuje wszystkie pliki jednocześnie, co powoduje pewne złe konflikty między plikami testowymi! co mogę zrobić ? –

+0

Spraw, aby każdy test nasłuchiwał na innym porcie - wystarczy wybrać liczbę losową (wystarczająco wysoką). –

+0

DOSKONAŁE ROZWIĄZANIE! To jest właściwy sposób, aby to zrobić. Jedna modyfikacja: powinieneś faktycznie zamknąć wynik app.listen, a nie samej aplikacji, tj .: (w before before) "instance = app.listen (3000);" ... a następnie (w AfterEach) "instance.close()" –

4

Oprócz Oved D odpowiedź.

Opisz swoją aplikację w Express app.js lub innego pliku:

module.exports = function (o) { 
    o = o || {}; 
    var app = express(); 

    // app.configure 
    // configure routes 
    if (o.someOption) { 
    // some additional test code 
    } 

    return app; 
} 

opisują testy w teście/01-some.js:

var expressApp = require('../express-app'); 
describe('some', function() { 

    // just describe needed vars 
    var app, server, port; 

    // describe setup 
    before(function (next) { 
    // create app when 
    app = expressApp({routes: /api\/some\/.*/ /* put here some test options ...*/}); 
    // creating listener with random port 
    server = app.listen(function() { 
     // store port when it ready 
     port = server.address().port; 
     // and go to tests 
     next(); 
    }); 
    }); 

    // tests 
    it('should return valid result', function (done) { 
    // do a simple request to /api/some 
    http.request({ 
     host: 'localhost', 
     port: port, 
     path: '/api/some' 
    }, function (res) { 
     if (res.err) throw new Error(res.err); 
     done(); 
    }); 
    }); 

    // teardown 
    after(function() { 
    // stop listening that port 
    server.close(); 
    }); 

}); 

Gotowe. ;-)

Teraz możesz utworzyć dowolną liczbę takich testów. Zalecamy włączenie tylko potrzebnych adresów URL i usług w testach z definiowaniem go przez przekazywanie paramerów do modułu express-app.js.


Aktualizacja:

Nie wiem, jak to działa w mocha ale lepiej przenieść before i after połączeń do init.js i załadować go z mocha --require init.js.

Plik powinien wyglądać tak:

// use it in your mocha tests 
global.setupEnv = function setupEnv (o, before, after) { 

    // just describe needed vars 
    var env = Object.create(null); 

    // setup 
    before(function (next) { 
     // create app 
     env.app = expressApp(o); 
     // creating listener with random port 
     env.server = env.app.listen(function() { 
      // store port when it ready 
      port = env.server.address().port; 
      env.app.log('Listening on ', env.port); 
      // and go to tests 
      next(); 
     }); 
    }); 

    // teardown 
    after(function() { 
     // stop listening that port 
     env.server.close(); 
    }); 

    return env; 
} 

I w badaniach:

// requiring dependencies 
var request = require('request'); 

describe('api', function() { 

    // describe setup 
    var env = global.setupEnv({ 
      routes: 'api/some' 
     }, before, after); 

    // tests 
    it('should pass', function (done) { 
     request('http://localhost:' + env.port, function (error, response, body) { 
      done(); 
     }); 
    }); 

});