2016-04-12 3 views
1

Ich habe ein sehr seltsames Problem getroffen: Ich versuche Unit Tests zu 100% Testabdeckung auf meiner Anwendung zu erreichen. Und natürlich habe ich ein paar Tests für meine Controller geschrieben, aber es scheint, als ob es keine Möglichkeit gibt, Async in Ember (2.4.0) mit ember-cli zu testen.Unit Tests Async-Funktionen in Ember-Controller

  1. Ich habe eine Funktion in der Steuerung, das dies tut:

    readObject() { 
        this.store.findRecord('myModel',1).then(function(obj) { 
         this.set('property1',obj.get('property2'); 
        }.bind(this)); 
    } 
    
  2. ich einen Test schreiben, der diese Funktion abdecken soll.

    test('action readObject', function (assert) { 
        const cont = this.subject(); 
        cont.readObject(); 
        assert.equal(cont.get('property1'), 'someValue); 
    }); 
    
  3. Obivously, würde dies assert nicht funktionieren, weil readObject-() Asynchron-Anruf ist, aber das ist nicht die Wurzel des Problems. Das Problem ist, dass dann ein Callback in this.store.findRecord ausgeführt wird - mein Controller ist bereits zerstört! So bekomme ich "Fehler beim Aufruf des zerstörten Objekts".

Mit anderen Worten - auch wenn ich meine Funktion in einem Versprechen wickeln und beide Funktionen wie diese umformatieren:

readObject() { 
    return new Promise(function(resolve) { 
     this.store.findRecord('myModel',1).then(function(obj) { 
      this.set('property1',obj.get('property2'); 
      resolve(); 
     }.bind(this)); 
    }.bind(this)); 
} 

und

test('action readObject', function (assert) { 
    const cont = this.subject(); 
    cont.readObject().then(function() { 
     assert.equal(cont.get('property1'), 'someValue); 
    }); 
}); 

es nicht funktionieren würde, denn nach Beim Ausführen von readObject() werden meine Controller sofort zerstört und warten nicht auf Callbacks. Es könnte also jeder async-Aufruf statt store.findRecord sein - es könnte zum Beispiel Ember.run.later sein.

Hat jemand das gleiche Problem? Ich habe viele Artikel gelesen, die ich nicht glauben kann, dass Ember mit einer so großen Community keine Möglichkeit bietet, asynchrone Komponententests durchzuführen.

Wenn jemand irgendwelche Hinweise hat - bitte geben Sie mir einen Hinweis, denn ich bin hier irgendwie verloren. Im Moment habe ich zwei Gedanken:

  1. Ich mache Controller falsch, ist Ember nicht annehmen, keine Asynchron-Operationen im Inneren. Aber selbst wenn ich asynchrone Aufrufe an Dienste übertrage - ich habe das gleiche Problem mit Schreibgerätentests für sie.

  2. ich meine Funktionen

    readObject() { 
        this.store.findRecord('myModel',1).then(this.actualReadObject.bind(this)); 
    } 
    
    actualReadObject(obj) { 
        this.set('property1',obj.get('property2'); 
    } 
    

zu zersetzen mindestens Rückrufe Körper mit Tests abgedeckt haben, aber dies bedeutet, dass ich 100% Testabdeckung nie in meiner App bekommen.

Vielen Dank im Voraus für Hinweise. :)

Antwort

1

Ich hatte ein ähnliches Problem und schaute auf die QUnit API - async Ich löste es. Probieren Sie Folgendes aus:

// ... in your controller ... 
readObject() { 
    return this.store.findRecord('myModel',1).then(function(obj) { 
     this.set('property1', obj.get('property2'); 
    }.bind(this)); 
} 

// ... in your tests, either with assert.async: ... 
const done = assert.async(); // asynchronous test due to promises usage 
Ember.run(function(){ 
    subject.readObject().then(function(){ 
     // once you reach this point you are sure your promise has been resolved 
     done(); 
    }); 
}); 


// or without assert.async 
let promise; 
Ember.run(function(){ 
    promise = subject.readObject(); 
}); 
return promise; 

In einem Fall von Komponententests mache ich auch andere Abhängigkeiten, zum Beispiel: speichern.

this.subject({ 
    property1: null, 
    store: { 
     findRecord(modelName, id){ 
     assert.equal(modelName, "myModel1"); 
     assert.equal(id, 1); 
     return new Ember.RSVP.Promise(function(resolve){ 
      resolve(Ember.Object.create({ property2: "a simple or complex mock" })); 
     }) 
     } 
    } 
}); 

Ich bin nicht sicher über den zweiten Fall (die ohne assert.async). Ich denke, es würde auch funktionieren, weil die Testsuite ein Versprechen gibt. Dies wird von QUnit erfasst, das auf das Versprechen wartet.

+0

Danke für einen Hinweis, aber das ist kein QUnit Problem, das ist ein Ember. :( –

+0

Zu der Zeit, als findRecord seinen Callback ausführt - der Controller selbst ist bereits zerstört. Soweit ich es verstehe - führt Ember den Test nur innerhalb eines Ember.run Calls aus. Wenn irgendetwas außerhalb dieses Aufrufs ausgeführt wird - ist die Anwendung bereits zerstört. :( –

+0

PS: Ich versuchte diesen Ansatz mit assert.async, aber es half auch nicht - findRecord Aufruf begann gerade mit Fehler fehlgeschlagen: "Kann Eigenschaft '_internalModel' von null nicht lesen, während Qnit wie erwartet funktionierte. –

0

Ich kopiere meine eigene Lösung hier, weil Codeformatierung in Kommentaren nicht zu gut ist.

test('async', function (assert) { 

    const cont = this.subject(); 
    const myModel = cont.get('store').createRecord('myModel'); // 

    // Make store.findRecord sync 
    cont.set('store',{ 
     findRecord(){ 
     return { then : function(callback) { callback(myModel); } } 
     } 
    }); 

    // Sync tests 
    assert.equal(cont.get('property2'), undefined); 
    cont.readObject(); // This line calls store.findRecord underneath 
    assert.equal(cont.get('property2'), true); 
}); 

Also, ich habe gerade store.findRecord in eine Synchronisierungsfunktion gedreht und es läuft perfekt. Und noch einmal - vielen Dank an Pavol für einen Hinweis. :)