我有一个角度控制器需要测试。此控制器调用服务以从服务器检索数据。该服务返回 ES6 承诺。
function MyController($scope, MyService) {
$scope.doSomething = function () {
MyService.foo().then() {
whatever...;
};
};
};
在我的茉莉花测试中,我也嘲笑了返回承诺的服务:
var resolve;
var reject;
createPromise = function () {
return new Promise(function (_resolve, _reject) {
resolve = _resolve;
reject = _reject;
});
};
var myServiceMock = {
doSomething: jasmine.createSpy('doSomething').and.callFake(createPromise)
};
beforeEach(module('someApp', function ($provide) {
$provide.value('MyService', myServiceMock);
}));
我手动调用全局解析(或拒绝),无论是否带有参数来检查我的控制器。
it('shall call the service', function () {
$scope = $rootScope.$new();
controller = $controller('MyService', { $scope: $scope });
controller.doSomething();
myService.resolve();
expect(whatever...);
});
问题是解析调用是异步的。所以我正在测试我的预期结果,同时运行 then 函数。
我没有返回 Promises,而是尝试返回简单的自定义对象,该对象会将 resolve 转换为同步调用,但事实证明 Promise 有一些特定的规则,这些规则太麻烦了,无法在模拟中重新实现(例如当你有 then.()。例如 catch().then 模式)。
有没有办法在茉莉花中以简单而同步的方式测试这种东西?
你需要告诉 Jasmine 你的测试是异步的,它应该等待它完成,然后再决定它失败了。为此,您可以在规范声明中添加一个 done
参数(it
调用),并在期望结束时调用done
:
it('shall call the service', function (done) {
$scope = $rootScope.$new();
controller = $controller('MyService', { $scope: $scope });
var promise =
controller.doSomething()
.then(function() {
expect(whatever...);
done();
});
myService.resolve();
});
使模拟自动解析的一种更简单方法是使用 Promise.resolve
方法:
doSomething: jasmine.createSpy('doSomething').and.returnValue(Promise.resolve())
然后,您无需调用myService.resolve
- 模拟会自动返回已解决的承诺。
我最近开始使用 jasmine-promise 模块,它使编写 promise 调用变得更加容易 - 并确保如果 promise 被拒绝,则会报告错误和调用堆栈,以便于调试。有了jasmine-promises
,这将变成:
it('shall call the service', function () {
$scope = $rootScope.$new();
controller = $controller('MyService', { $scope: $scope });
return controller.doSomething()
.then(function() {
expect(whatever...);
});
});