我在测试控制器的价值时遇到了麻烦,这些价值是在服务返回的承诺范围内设定的。我使用Sinon来存根服务(Karma运行测试,Mocha作为框架,Chai用于断言)。
我对快速解决方案的兴趣不如我理解问题。我已经阅读了很多内容,我在代码和测试下面有一些笔记。
这是代码。
.controller('NavCtrl', function (NavService) {
var vm = this;
NavService.getNav()
.then(function(response){
vm.nav = response.data;
});
})
.service('NavService', ['$http', function ($http) {
this.getNav = function () {
return $http.get('_routes');
};
}]);
以下是测试:
describe('NavCtrl', function () {
var scope;
var controller;
var NavService;
var $q;
beforeEach(module('nav'));
beforeEach(inject(function($rootScope, $controller, _$q_, _NavService_){
NavService = _NavService_;
scope = $rootScope.$new();
controller = $controller;
}));
it('should have some data', function () {
var stub = sinon.stub(NavService, 'getNav').returns($q.when({
response: {
data: 'data'
}
}));
var vm = controller("NavCtrl", {
$scope: scope,
NavService: NavService
});
scope.$apply();
stub.callCount.should.equal(1);
vm.should.be.defined;
vm.nav.should.be.defined;
});
});
正在调用存根,即测试通过,并且vm
已定义,但vm.nav
从不获取数据,测试失败。我认为,如何处理违约的承诺是罪魁祸首。一些说明:
根据reading elsewhere,我正在调用scope.$apply
来设置值,但由于范围未注入原始控制器,我不是积极的,将做到这一点。此article指向angular docs on $q。
另一篇文章推荐using $timeout,因为"实际完成了承诺"。该文章还建议使用" sinon-as-promise,"我上面没做过的事情。我试过了,但没有看到差异。
此Stack Overflow回答使用scope.$root.$digest()因为"如果您的范围对象的值来自promise结果,则需要调用范围。$ root。$ digest() &#34 ;.但同样,同样的测试失败。而且,这可能是因为我没有使用范围。
至于保留承诺,我也尝试了sinon sandbox way,但结果是一样的。
我尝试使用$scope
重写测试,以确保它不是vm
style的问题,但测试仍然失败。
最后,我可能是错的:存根和承诺可能不是问题,它是我错过的不同和/或明显的东西。
非常感谢任何帮助,如果我能澄清以上任何内容,请告诉我。
答案 0 :(得分:1)
抱歉,您可以快速解决所有问题:
var stub = sinon.stub(NavService, 'getNav').returns($q.when({
response: {
data: 'data'
}
}));
您的承诺已解决为包含response.data
的对象而不只是data
通过代码https://plnkr.co/edit/GL1Xuf?p=preview
我经常陷入同样的陷阱。所以我开始分别定义从方法返回的结果。然后,如果该方法是异步的,我将此结果包装在像$q.when(stubbedResult)
这样的承诺中,这允许我轻松地对实际结果运行期望,因为我将存根结果保存在变量中,例如。
it('Controller should have some data', function () {
var result = {data: 'data'};
var stub = sinon.stub(NavService, 'getNav').returns($q.when(result));
var vm = controller(/* initController */);
scope.$apply();
stub.callCount.should.equal(1);
vm.nav.should.equal(result.data)
})
另外一些测试调试技巧会派上用场。最简单的方法是在控制台上转储一些数据,以检查某些地方返回的内容。当然,使用实际的调试器是可取的。
$rootScope.apply()
行(就在执行之前)设置断点NavService.getNav().then
处理程序中放置一个断点,以查看它是否被调用以及它被调用的内容$rootScope.$apply()
行。现在调试器应该达到上一步设置的断点 - 那就是它。答案 1 :(得分:0)
我认为你应该使用chai-as-promised
然后从诸如
之类的承诺中断言 doSomethingAsync().should.eventually.equal("foo");
或者使用async await
it('should have some data', async function () {
await scope.$apply();
});
您可能需要移动getNav()
调用init
有点函数然后针对该init
函数进行测试