在true
内解决了承诺后,我正在尝试测试值是否已更改为$onInit
。我尽可能地关注example in this Stack Overflow question/answer。这是我的代码:
class TestCtrl {
constructor(SearchService) {
this.testValue = false;
this.SearchService = SearchService;
}
$onInit() {
this.SearchService.getResults()
.then(function () {
this.testValue = true;
});
}
}
TestCtrl.$inject = ['SearchService'];
这是我试图运行的测试(使用mocha,chai,sinon):
it('should work', function() {
ctrl = $componentController('test', {
SearchService: SearchService
}, {});
sinon.stub(SearchService, 'getResults').resolves({response:{data: 'data'}});
ctrl.$onInit();
$rootScope.$apply();
ctrl.testValue.should.equal(true);
});
我应该在ctrl.testValue
内测试then
吗?另外,使用this example是一个坏主意,因为该示例不使用带有$onInit
生命周期钩子的组件?
据我所读,no,“在测试中不要使用expect。”但根据我的read elsewhere,我不太确定。
如果我遗漏了一些关于如何测试承诺(可能是存根不是要走的路?)和/或如何测试$onInit
生命周期中发生的事情,我不会感到惊讶钩。
如果问题需要更多细节,请询问,我会尽力添加它们。
答案 0 :(得分:2)
修改:结帐$onInit
方法:
$onInit() {
this.SearchService.getResults()
.then(function () {
// `this` in anonymous function is reffering to window not the controller instance
this.testValue = true;
});
}
$onInit() {
var self = this;
self.SearchService.getResults()
.then(function () {
self.testValue = true;
});
}
这是在angularjs
中测试异步代码的方法 - 它像同步代码一样进行测试。存根'执行$ rootScope时会返回返回的promise。$ apply()。
从stub.resolves()
返回的承诺不是一个有希望的承诺。无法使用$rootScope
触发解决,因为它不是角度世界的一部分。它的承诺解析队列与其他东西联系在一起,因此需要像通常测试异步代码一样进行测试。
Angular并不依赖于JavaScript的本机Promise实现 - 它使用了Q&#39}承诺库的轻量级实现,该库包含在名为$q
的服务中
您引用的answer使用相同的服务来创建并从存根中返回承诺
为了让代码工作 - 像测试同步代码一样进行测试 - 你应该返回一个$q
承诺(通过在$q.when(value)
中包装一个值),调用$rootScope.$apply()
将执行then
块中的代码,然后继续$rootScope.$apply()
行下面的代码。
以下是一个例子:
it('Sinon should work with angular promises', function () {
var resolved = 'resolved';
var promise = $q.when(resolved);
// Our async function
var stub = sinon.stub().returns(promise);
// Callback to be executed after the promise resolves
var handler = sinon.stub();
stub().then(handler); // async code
// The handler will be called only after $rootScope.$apply()
handler.callCount.should.equal(0);
// triggers digest which will resolve `ready` promises
// like those created with $q.when(), $q.resolve() or those created
// using the $q.defer() and deferred.resolve() was called
// this will execute the code inside the appropriate callback for
// `then/catch/finally` for all promises and then continue
// with the code bellow -> this is why the test is considered `synchronous`
$rootScope.$apply();
// Verify the handler was called and with the expected value
handler.callCount.should.equal(1);
handler.should.have.been.calledWith(resolved);
})
答案 1 :(得分:1)
首先,您应该阅读how Mocha expects you to test async code。
从快速位开始:
then
。then
内断言测试。实际上,它通常是断言承诺的已解决价值的唯一方法。您的测试代码的主要问题是它尝试在结果可用之前断言(因为承诺在稍后的时间点解析,它们是asynchronous)。
您尝试测试的代码的主要问题是无法知道init函数何时已解决。
我们可以通过等待存根SearchService.getResults
来解决(因为我们在测试中控制存根)来处理#2,但这假设对onInit
的实现有太多的了解,所以是一个糟糕的黑客。
相反,我们只需在TestCtrl
中返回承诺,就可以修复onInit
中的代码:
//main code / TestCtrl
$onInit() {
return this.SearchService.getResults()
.then(function () {
this.testValue = true;
});
}
现在我们可以在测试执行期间发生的事情之前等待对onInit
的任何调用解决!
要修复测试,我们首先在包装测试函数中添加一个参数。 Mocha会看到这个并传递一个你可以在测试结束时调用的函数。
it('should work', function(done) {
这使它成为异步测试。现在让我们修复测试部分:
ctrl.$onInit().then( () => {
ctrl.testValue.should.equal(true);
done(); // signals to mocha that the test is finished ok
}).catch(done); // pass any errors to the callback
您可能还会发现this answer enlightening(如果它可以帮助您,则可以提供支持)。阅读之后你也可以理解为什么Mocha也支持通过从测试中返回一个promise而放弃done
回调。进行更短的测试:
return ctrl.$onInit().then( () => {
ctrl.testValue.should.equal(true);
});
答案 2 :(得分:-1)
const ref = firebase.database().ref('order/');
ref.on('child_added', snapshot => {
// snapshot now contains the data of -KmDWQ...
snapshot.child("items").forEach((itemSnapshot) => {
console.log(itemSnapshot.key, itemSnapshot.val().name);
});
});
未返回承诺。使用sinon.stub(SearchService, 'getResults').resolves({response:{data: 'data'}});
。
我建议这样做:
$q
您无需在当时测试ctrl = $componentController('test', {
SearchService: SearchService
}, {});
let deferred =$q.defer();
deferred.resolve({response:{data: 'data'}});
sinon.stub(SearchService, 'getResults').resolves(deferred.promise);
ctrl.$onInit();
$rootScope.$apply();
ctrl.testValue.should.equal(true);
。一般来说,我建议不要在你的规范中ctrl.testValue
内断言。如果承诺永远不会得到解决,规格将不会失败。这实际上可以给你一种虚假的安全感,你的测试没有做任何事情。但那只是我的个人意见。
一旦存根返回一个promise,你的测试就会通过。理想情况下,如果服务正在进行http调用,我建议使用$ httpBackend。
欢呼声。