2017-08-02 3 views
0

Ich habe es mit einem Code-Mixing-Knoten-Stil Callbacks und Bluebird verspricht, und ich muss einige Unit Tests dafür schreiben.Test Callback Aufruf am Ende der Versprechen Kette

Insbesondere cache.js macht die init() Funktion, die mit Versprechen funktioniert. Es wird dann von der doSomething()-Funktion in einer anderen Datei (z. B. index.js) aufgerufen, die wiederum einen Rückruf akzeptiert, der am Ende von init() aufgerufen werden muss.

Pseudocode ist wie folgt:

// [ cache.js ] 
function init() { 
    return performInitialisation() 
    .then((result) => return result); 
} 


// [ index.js ] 
var cache = require('./cache'); 

function doSomething(callback) { 
    console.log('Enter'); 

    cache.init() 
    .then(() => { 
     console.log('Invoking callback'); 
     callback(null); 
    }) 
    .catch((err) => { 
     console.log('Invoking callback with error'); 
     callback(err); 
    }); 

    console.log('Exit'); 
} 

Ein möglicher Komponententest werden könnte (nur relevanten Code angezeigt):

// [ index.test.js ] 
... 
var mockCache = sinon.mock(cache); 
... 
it('calls the callback on success', function(done) { 
    mockCache.expects('init') 
    .resolves({}); 

    var callback = sinon.spy(); 

    doSomething(callback); 
    expect(callback).to.have.been.calledOnce; 
    done(); 
}); 

Dieser Test besteht jedoch die Erwartung auch not.have.been.calledOnce ändernden gibt, die ist falsch.

Auch Konsolenprotokolle sind in der richtigen Reihenfolge:

Enter 
Exit 
Invoking callback 

Ich habe an mehreren Möglichkeiten gesucht, von denen keines gearbeitet:

  • Mit chai-as-versprochen, z.B. expect(callback).to.eventually.have.been.calledOnce;

  • Refactoring doSomething() einfach sein:

    Funktion doSomething (Callback) { cache.init() .asCallback (Callback); }

Kann mir jemand helfen zu verstehen, was ich tue, falsch und wie kann ich es beheben bitte?

Antwort

0

Konsolenprotokolle sind in der richtigen Reihenfolge

Die Protokolle in der richtigen Reihenfolge sind, weil Ihre Promise async Bedeutung sein wird, zumindest, ruft die interne Konsole anmeldet then & catch auf laufen der nächste Tick.

Wie, warum der Test versagt das Ergebnis einer Reihe von Fragen ist, wird zuerst ein Sie erscheinen nicht sinon-chai richtig konfiguriert haben, oder bestenfalls Ihre calledOnce Behauptung nicht in kickt. Nur um zu bestätigen, die Spitze Ihrer Testdatei sollte so etwas wie:

const chai = require("chai"); 
const sinonChai = require("sinon-chai"); 

chai.use(sinonChai); 

Falls Sie Fragen haben und es funktioniert immer noch nicht richtig könnte dann wert sein ein Problem auf dem sinon-chai lib Öffnen jedoch eine einfache Abhilfe ist zu sinon assertions zB wechseln

sinon.assert.calledOnce(callback) 

Zweitens, wenn Sie dies schließlich beheben, werden Sie wahrscheinlich feststellen, dass der Test jetzt jedes Mal fehlschlägt. Grund dafür ist, dass Sie das gleiche Problem in Ihrem Test haben, das Sie bei Ihrer Protokollierung haben - Ihre Behauptung, bevor das interne Versprechen eine Chance hatte zu lösen.Einfachste Weg, dies zu fixieren ist eigentlich mit Ihrem done Handler von Mokka als Ihre Behauptung

mockCache.expects('init').resolves({}); 
doSomething(() => done()); 

Mit anderen Worten, wenn done get genannt dann wissen Sie, der Rückruf aufgerufen wurde :)

+0

Vielen Dank für Ihre Antwort. Wenn ich 'doSomething (() => done());' 'dann kann ich die Fehlerbedingung nicht testen, richtig? Ich meine, ich werde nicht sehen, ob der Rückruf mit dem Fehlerargument aufgerufen wird. – rippeltippel

+0

@rippeltippel Ihr Umgang mit dem Rückruf, so dass die Tatsache, dass "fertig" aufgerufen wird und der Test besteht, ist Ihr Scheck. Wenn Callback aus irgendeinem Grund nicht aufgerufen wird, würde Ihr Test Timeout sein. – James

+0

Macht Sinn, danke. – rippeltippel

0

Nach James 'Kommentar I Meine Tests wie folgt wieder besucht:

it('calls the callback on success', function(done) { 
    mockCache.expects('init') 
    .resolves({}); 

    doSomething(done); 
}); 

it('calls the callback on error', function(done) { 
    mockCache.expects('init') 
    .rejects('Error'); 

    doSomething((err) => { 
    if (err === 'Error') { 
     done(); 
    } else { 
     done(err); 
    } 
    }); 
});