2016-01-03 17 views
10

Sto eseguendo la mia suite di test utilizzando mocha, tramite gulp-jsx-coverage e gulp-mocha. Tutti i miei test funzionano e passano/falliscono come previsto. Tuttavia, alcuni dei miei moduli testati eseguono richieste HTTP alla mia API tramite la libreria superagent.Mocha test suite che emette errori quando si tenta di connettersi all'API

In fase di sviluppo, eseguo anche la mia API allo localhost:3000 insieme alla mia app lato client, quindi l'URL a cui i test sul lato client stanno tentando di accedere. Durante il test, tuttavia, l'API di solito non è in esecuzione. Il risultato è il seguente errore in qualsiasi momento una richiesta ottiene attraverso:

Error in plugin 'gulp-mocha' 
Message: 
    connect ECONNREFUSED 
Details: 
    code: ECONNREFUSED 
    errno: ECONNREFUSED 
    syscall: connect 
    domainEmitter: [object Object] 
    domain: [object Object] 
    domainThrown: false 
Stack: 
Error: connect ECONNREFUSED 
    at exports._errnoException (util.js:746:11) 
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:983:19) 

Ho provato spegnendo tutti i metodi sul (alias come request) biblioteca superagent in un aiuto globale, in questo modo:

function httpStub() { 
    return { 
    withCredentials:() => { 
     return { end:() => {} }; 
    } 
    }; 
}; 

beforeEach(function() { 
    global.sandbox = sinon.sandbox.create(); 

    global.getStub = global.sandbox.stub(request, 'get', httpStub); 
    global.putStub = global.sandbox.stub(request, 'put', httpStub); 
    global.patchStub = global.sandbox.stub(request, 'patch', httpStub); 
    global.postStub = global.sandbox.stub(request, 'post', httpStub); 
    global.delStub = global.sandbox.stub(request, 'del', httpStub); 
}); 

afterEach(function() { 
    global.sandbox.restore(); 
}); 

Ma per qualche motivo, quando si verificano alcuni test, i metodi non vengono cancellati e quindi raggiungo l'errore ECONNREFUSED. Ho triplicato il controllo e no dove sto ripristinando la sandbox o altri stub.

C'è un modo per risolvere il problema che sto incontrando o una soluzione più pulita per questo?

+0

è il comportamento deterministico?Stai scrivendo che i problemi si verificano per "alcuni test" - è sempre lo stesso insieme di test che falliscono o che un determinato test può passare in un test-run e fallire nell'altro? –

+0

@TomasKulich non fallisce sullo stesso test ogni volta, ma fallisce all'interno di un certo sottoinsieme di test. Questo è solo perché questi sono i test le cui azioni alla fine si tradurranno in chiamate all'API. Se eseguo un singolo file di test che in precedenza era stato cancellato, sarebbe passato. Sembra che si verifichi solo quando si esegue l'intera suite, presumibilmente a causa dei metodi 'request' che in qualche modo diventano non citati – Jakemmarsh

risposta

4

Il problema potrebbe essere causato dal fatto di non eseguire correttamente le cose asincrone nel test. Immaginate seguente esempio:

it('is BAD asynchronous test',() => { 
    do_something() 
    do_something_else() 
    return do_something_async(/* callback */() => { 
    problematic_call() 
    }) 
}) 

Quando Mocha trova un tale test viene eseguito (sincrono) do_something, do_something_else e do_something_async. In quel momento, dal punto di vista di Mochas, il test è finito, Mocha esegue dopo Each() per questo (cosa è male, lo problematic_call è ancora da chiamare!) E (cosa ancora peggiore), inizia a eseguire il prossimo test!

Ora, i test in esecuzione (e prima di Each e dopoEach) in modo parallelo possono portare a risultati davvero strani e imprevedibili, quindi non sorprende che qualcosa sia andato storto (probabilmente dopo ogni chiamata è stata chiamata nel mezzo di alcuni test che hanno portato a unstubbing l'ambiente)

Cosa fare con esso:

segnale sempre di Mocha, quando finisce il test. Questo può essere fatto sia restituendo un oggetto di promessa, o, chiamando done callback:

it('is BAD asynchronous test', (done) => { 
    do_something() 
    do_something_else() 
    return do_something_async(/* callback */() => { 
    problematic_call() 
    done() 
    }) 
}) 

https://mochajs.org/

In questo modo Mocha 'sa', quando la vostra estremità di test e solo allora si corre il prossimo test.

+0

Se questo è davvero un tuo problema, potresti ancora avere delle deboli operazioni di debugging - omg omg dove diavolo è la callback/prometto che non sto aspettando. Se questo è il caso, scriverò alcuni trucchi utili che puoi usare. –

+0

Sembra che tu avessi ragione. Ero a conoscenza del callback 'done' per i test asincroni e pensavo di usarlo ovunque fosse necessario, ma alcuni dei miei altri test dovevano essere asincroni. La correzione di una manciata di test non funzionanti significava anche che avrei potuto rimuovere quei brutti stub globali su 'request' e solo stub nei test rilevanti. Grazie! – Jakemmarsh

+0

Perfetto, sono contento che sia stato d'aiuto. Inoltre, ricorda che l'opzione abbastanza fine per la funzione asincrona è quella di restituire un oggetto Promise (devi comunque concatenare correttamente le Promises). –

1

request è già stato richiesto dall'applicazione, quindi non importa se lo stub nei test.

È necessario utilizzare qualcosa come rewire e sostituire lo request richiesto dall'applicazione con la versione stub.

Qualcosa di simile dovrebbe aiutare

var request = require('superagent'), 
    rewire = require('rewire'), 
    sinon = require('sinon'), 
    application = rewire('your-app'), 
    rewiredRequest; 

function httpStub() { 
    return { 
     withCredentials:() => { 
      return { end:() => {} }; 
     } 
    }; 
}; 

beforeEach(function() { 
    var requestStub = { 
     get: httpStub, 
     put: httpStub, 
     patch: httpStub, 
     post: httpStub, 
     del: httpStub 
    }; 

    // rewiredRequest is a function that will revert the rewiring 
    rewiredRequest = application.__set__({ 
     request: requestStub 
    }); 
}); 

afterEach(function() { 
    rewiredRequest(); 
}); 
Problemi correlati