我遇到了一个非常奇怪的问题:我正在尝试进行单元测试以在我的应用程序上实现100%的测试覆盖率。 当然我为我的控制器编写了一些测试,但似乎没有办法使用ember-cli在Ember(2.4.0)中测试任何异步。
我在控制器中有一个功能:
readObject() {
this.store.findRecord('myModel',1).then(function(obj) {
this.set('property1',obj.get('property2');
}.bind(this));
}
我正在编写一个应该涵盖此功能的测试。
test('action readObject', function (assert) {
const cont = this.subject();
cont.readObject();
assert.equal(cont.get('property1'), 'someValue);
});
很明显,这个断言不起作用,因为readObject()是异步调用,但这不是问题的根源。问题是然后正在执行this.store.findRecord中的回调 - 我的控制器已被销毁!所以我得到了“在被破坏的对象上调用set”错误。
换句话说 - 即使我将我的函数包装在一个promise中并重新格式化这两个函数:
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));
}
和
test('action readObject', function (assert) {
const cont = this.subject();
cont.readObject().then(function() {
assert.equal(cont.get('property1'), 'someValue);
});
});
它不起作用,因为在执行readObject()后,我的控制器立即被销毁,而不是等待任何回调。 因此,它可以是任何异步调用而不是store.findRecord - 例如,它可以是Ember.run.later。
有人有同样的问题吗?我读过很多文章,我不敢相信Ember这么大的社区没有提供进行异步单元测试的方法。
如果有人有任何线索 - 请给我一个提示,因为我有点迷失在这里。目前我有两个想法:
我让控制器出错了,Ember并没有假设其中有任何异步操作。但即使我将异步调用移到服务上 - 我为它们编写单元测试也遇到了同样的问题。
我必须将我的功能分解为
readObject() {
this.store.findRecord('myModel',1).then(this.actualReadObject.bind(this));
}
actualReadObject(obj) {
this.set('property1',obj.get('property2');
}
让至少回调体覆盖测试,但这意味着我从未在我的应用程序中获得100%的测试覆盖率。
提前感谢您提供任何线索。 :)
答案 0 :(得分:1)
我遇到了类似的问题,看着QUnit API - async我解决了它。试试以下:
// ... 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;
在单元测试的情况下,我也会模拟其他依赖项,例如:store。
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" }));
})
}
}
});
我不确定第二种情况(没有assert.async
的情况)。我认为它也会起作用,因为测试套件会返回一个承诺。这会被等待承诺的QUnit所记录。
答案 1 :(得分:0)
我在这里复制我自己的解决方案,导致评论中的代码格式化不太好。
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);
});
所以,我只是将store.findRecord变成了一个同步函数,它运行得很完美。再一次 - 非常感谢Pavol提供线索。 :)