我写了一个离子应用程序。我开始为它添加测试我遇到$resources
的问题。在这种情况下,我有这个控制器:
.controller('newAccountCtrl', function($scope, $window, $rootScope, API, $ionicPopup, $state) {
$scope.newData = {};
$scope.$on('$ionicView.enter', function() {
$scope.newData = {};
});
$scope.newInfo = function() {
API.newAccountInfo.update({
restCode: $scope.newData.restore_code
}, $scope.newData, function(res, header) {
$scope.comty = 'update';
$window.location.href = '#/login';
}, function(err) {
if (err.data == null)
$rootScope.popup("Error", "no connection");
else
$rootScope.popup('error', err.data.error);
});
}
})
在服务中,我在函数中使用$resources
发出请求:
angular.module('starter.services', [])
.factory('API', function($rootScope, $resource, $ionicPopup, $ionicLoading, $window) {
return {
newAccountInfo: $resource(base + '/restoreinfo/:restCode', {
restCode: '@_restCode'
}, {
update: {
method: 'PUT'
}
}, {
stripTrailingSlashes: false
});
}
并在我的测试中使用以下代码:
describe('newAccountCtrl', function() {
var controller,
deferredLogup, window, scope,
$rootScope,
$q, store, API,
PROMISE = {
resolve: true,
reject: false
};
beforeEach(angular.mock.module('starter'));
beforeEach(module('starter.controllers'));
beforeEach(module('starter.services'));
beforeEach(module(function($provide, $urlRouterProvider) {
$provide.value('$ionicTemplateCache', function() {});
$urlRouterProvider.deferIntercept();
}));
beforeEach(inject(function($controller, _$rootScope_, $q, _API_, _$window_) {
$q = $q;
deferredLogup = $q.defer();
$rootScope = _$rootScope_;
spyOn($rootScope, 'popup')
scope = $rootScope.$new();
API = _API_;
window = _$window_;
spyOn(API.newAccountInfo, 'update').and.callThrough(function(callback) {
deferredLogup.promise.then(callback);
return deferredLogup.promise;
});
controller = $controller('newAccountCtrl', {
'$scope': scope,
'API': API,
'$window': window
});
}));
it('expect API.newAccountInfo to Have Been Called', function() {
scope.getloghist();
expect(API.newAccountInfo.upadate).toHaveBeenCalled();
})
it('on success ', function() {
scope.newInfo();
deferredLogup.resolve();
scope.$digest();
expect(scope.comty).toBeDefined();
});
it('on unsuccessful', function() {
scope.newInfo();
deferredLogup.reject();
scope.$digest()
expect($rootScope.popup).toHaveBeenCalled();
});
});
首先期望它通过,但第二个“成功”返回错误
“预期未定义要定义”。
我是编写单元测试的新手。我在这里缺少什么?
答案 0 :(得分:0)
在你的间谍中:
spyOn(API.newAccountInfo, 'update').and.callThrough(function(callback){
deferredLogup.promise.then(callback);
return deferredLogup.promise;
});
.and.callThrough
仅跟踪该功能。它不会模拟它(因此你传递它的功能什么都不做)。来自文档:
通过使用and.callThrough链接间谍,间谍仍将跟踪对它的所有调用,但此外它将委托给实际的实现。
对于'它运行你正在监视的实际功能'这是一种奇特的说法。
您希望.and.callFake
跟踪并模拟传递的函数。
spyOn(API.newAccountInfo,'update').and.callFake(function(callback){
deferredLogup.promise.then(callback);
return deferredLogup.promise;
});
所以,你正在嘲笑这个匿名函数:
function(callback){
deferredLogup.promise.then(callback);
return deferredLogup.promise;
}
此^函数现在充当API.newAccountInfo.update
。此函数采用第一个参数并将其作为回调运行。去看看你正在运行的地方API.newAccountInfo.update
:
API.newAccountInfo.update({
restCode: $scope.newData.restore_code
}, $scope.newData, function(res, header) {
$scope.comty = 'update';
$window.location.href = '#/login';
}, function(err) {
if (err.data == null)
$rootScope.popup("Error", "no connection");
else
$rootScope.popup('error', err.data.error);
});
//Simplifying this:
API.newAccountInfo.update([Object], [Object], successCallback, errorCallback)
您将回调作为第三和第四参数传递,而不是第一个。但是你的模拟试图运行第一个参数。所以它试图将一个对象(而不是一个函数)提供给deferredLogup.promise.then
。
你的间谍应该是这样的:
spyOn(API.newAccountInfo,'update').and.callFake(function(param1, param2, callback, errorCallback){
deferredLogup.promise.then(callback);
return deferredLogup.promise;
});
希望这有帮助。