2013-03-03 23 views
8

Ho scritto alcuni metodi Meteor per la mia applicazione contenente vari blocchi di logica aziendale. Ora mi piacerebbe scrivere test unitari per questi metodi. Con test di unità, ho espressamente dire prove veloci che non lo fanno:Come posso testare i miei metodi meteorologici?

  • Eseguire XHR o
  • scrivere nel database

Come posso fare per fare questo? Il mio pensiero attuale è che quando avvierò il server Meteor in una configurazione di test, dovrei sostituire le mie collezioni con collezioni fittizie (passando new Meteor.Collection(null)) e far eseguire i miei test unitari sul lato server, invocando Meteor.call() su ciascuno dei miei metodi a loro volta da lì. Non sono del tutto sicuro di come avrò dato il via ai test, forse avrei voluto creare un URL personalizzato /tests nella mia applicazione che li licenziò. Questo approccio sembra ragionevole? Ci sono librerie/pacchetti là fuori che renderebbero più facili le prove di scrittura dei miei metodi?

risposta

1

Va bene, ecco cosa ho inventato per testare i miei metodi. Sarò il primo ad ammettere che c'è molto spazio per migliorare in questo!

In primo luogo, nel mio file server.coffee Ho il seguente codice:

Meteor.startup -> 
    return unless Meteor.settings["test"] 
    require = __meteor_bootstrap__.require 
    require("coffee-script") 
    fs = require("fs") 
    path = require("path") 
    Mocha = require("mocha") 

    mocha = new Mocha() 
    files = fs.readdirSync("tests") 
    basePath = fs.realpathSync("tests") 
    for file in files 
    continue unless file.match(/\.coffee$/) or file.match(/\.js$/) 
    continue if file[0] == "." 
    filePath = path.join(basePath, file) 
    continue unless fs.statSync(filePath).isFile() 
    mocha.addFile(filePath) 
    mocha.run() 

Prima di tutto questo codice solo se corre Meteor.settings [ "test"] è stato definito, che posso fare quando corro i miei test localmente, ma che non dovrebbero mai essere veri nella produzione. Quindi cerca nella directory "tests" per i file javascript o coffeescript (le sottodirectory non vengono cercate nella mia implementazione, ma sarebbe facile aggiungerle) e le aggiunge a un'istanza mocha. Sto utilizzando l'eccellente libreria di test javascript mocha, combinata con la libreria di asserzione chai.

Tutto questo codice è racchiuso all'interno di una chiamata Meteor.startup in modo che i test dell'unità vengano eseguiti all'avvio del server. Questo è particolarmente bello perché Meteor esegue automaticamente i miei test ogni volta che cambio uno qualsiasi del mio codice.A causa della decisione di isolare il database e non eseguire XHR, i miei test vengono eseguiti in pochi millisecondi, quindi non è molto fastidioso.

Per le prove stesse, ho bisogno di fare

chai = require("chai") 
should = chai.should() 

a tirare nella biblioteca asserzione. Ci sono ancora un paio di problemi difficili da risolvere, però. Prima di tutto, le chiamate al metodo Meteor falliranno se non sono avvolte in una fibra. Io attualmente non hanno una buona soluzione a questo problema, ma ho creato la funzione itShould per sostituire la funzione di moka it e avvolgere il corpo di prova all'interno di una fibra:

# A version of mocha's "it" function which wraps the test body in a Fiber. 
itShould = (desc, fn) -> 
    it(("should " + desc), (done) -> (Fiber -> 
    fn() 
    done()).run()) 

Il prossimo è il problema di, per i test scopi, sostituendo le mie raccolte con raccolte fittizie. Questo è molto difficile da fare se si segue la pratica standard di Meteor di inserire le proprie raccolte in variabili globali. Tuttavia, se si effettuano le raccolte proprietà su un oggetto globale, è possibile farlo. Crea semplicemente le tue collezioni tramite myApp.Collection = new Meteor.Collection("name"). Poi, nei test, si può avere un before funzione di finto la collezione:

realCollection = null 
before -> 
    realCollection = myApp.Collection 
    myApp.Collection = new Meteor.Collection(null) 
after -> 
    myApp.Collection = realCollection 

In questo modo, la vostra collezione viene deriso per tutta la durata della prova, ma poi è restaurato in modo da poter interagire con il app normalmente. Alcune altre cose sono possibili per deridere tramite una tecnica simile. Ad esempio, la funzione globale Meteor.userId() funziona solo per le richieste avviate dal client. In realtà ho depositato a bug contro Meteor per vedere se sono in grado di fornire una soluzione migliore a questo problema, ma per ora sto solo sostituendo la funzione con la mia versione per il test:

realUserIdFn = null 
before -> 
    realUserIdFn = Meteor.userId 
    Meteor.userId = -> "123456" 
after -> 
    Meteor.userId = realUserIdFn 

Questo approccio funziona per un po ' parti di Meteor, ma non tutte. Ad esempio, non ho trovato un modo per testare i metodi che invocano ancora this.setUserId, perché non penso che ci sia un buon modo per deridere quel comportamento. Nel complesso, però, questo approccio sta funzionando per me ... Adoro essere in grado di rieseguire i miei test automaticamente quando cambio il codice, e l'esecuzione di test in isolamento è solo generalmente una buona idea. È anche molto conveniente che i test sul server possano bloccarli, rendendoli più semplici da scrivere senza catene di callback. Ecco come si presenta un test:

describe "the newWidget method", -> 
    itShould "make a new widget in the Widgets collection", -> 
    widgetId = Meteor.call("newWidget", {awesome: true}) 
    widget = myApp.Widgets.findOne(widgetId) 
    widget.awesome.should.be.true 
0

Sto usando jasmine per testare un'applicazione Meteor più grande su cui sto lavorando. Può fare molto di più dei test unitari e funziona abbastanza bene. Un post di questo post è sul mio blog. Per ora posso darti questo CoffeeScript:

if were_testing() 
    describe 'something', -> 
    it 'should be greater than 0', -> 
     expect(theThing).toBeGreaterThan 0 

were_testing = -> document.location.pathname.replace(/^\/([^\/]*).*$/, '$1') == 'tests' 

jasmine_test = -> 
    jasmineEnv = jasmine.getEnv() 
    jasmineEnv.updateInterval = 1000 

    htmlReporter = new jasmine.HtmlReporter() 
    jasmineEnv.addReporter htmlReporter 

    jasmineEnv.execute() 

Questo codice viene eseguito in un browser. È possibile eseguirlo in un'istanza di casperjs se si desidera copiarlo. Dal momento che sta eseguendo un'inizializzazione di Meteor sul client, eseguirà query XHR e database, ma è possibile scrivere facilmente test che non faranno ulteriori query. Oppure scrivi un sottoinsieme di funzioni attivate durante la visita/unittest

La nostra roba non è ancora in produzione, ma il deployscript elimina semplicemente il codice jasmine sopra e tutti i file *.spec.coffee.

Voglio collegarlo a Jenkins per ottenere una corretta configurazione di integrazione continua ma non ho trovato il tempo per impostare Jenkins più delle basi. Ho anche giocato con l'utilizzo di casperjs per la navigazione headless, che ha funzionato abbastanza bene.

È inoltre possibile adottare un approccio diverso inserendo il codice di prova in tests/ (non eseguito da Meteor) e quindi utilizzare require. Ho subito provato questo e l'ho trovato abbastanza noioso.

+0

Forse non lo capisco, ma sembra che questo codice venga eseguito nel browser, giusto? In tal caso, penso che sia piuttosto difficile testare i metodi da soli. A meno che non stia succedendo qualcosa di speciale, le tue chiamate al metodo eseguiranno XHR e scritture e materiale del database, no? –

Problemi correlati