问题
I have a unit test for an Angular service in which I test that a cache $cacheFactory is cleared after a call has been made for a save() method that does an http post to the backend. In 1.0.7 this test passed in Karma and Jasmine Specrunner.html, but after migrating to Angular 1.2.0 it fails. I have not changed any code in the service or in the spec file. The cache is cleared in production when I check it manually. Any ideas?
EDIT: Plunk of the error in action: http://plnkr.co/edit/1INhdM
The error message is:
Field service save() should clear field array from cache.
Expected 2 to be 1.
Error: Expected 2 to be 1.
at new jasmine.ExpectationResult (http://localhost:1234/js/test/lib/jasmine/jasmine.js:114:32)
at null.toBe (http://localhost:1234/js/test/lib/jasmine/jasmine.js:1235:29)
at http://localhost:1234/js/test/spec/field-serviceSpec.js:121:25
at wrappedCallback (http://localhost:1234/js/angular-1.2.0.js:10549:81)
at http://localhost:1234/js/angular-1.2.0.js:10635:26
at Scope.$eval (http://localhost:1234/js/angular-1.2.0.js:11528:28)
at Scope.$digest (http://localhost:1234/js/angular-1.2.0.js:11373:31)
at Scope.$delegate.__proto__.$digest (<anonymous>:844:31)
at Scope.$apply (http://localhost:1234/js/angular-1.2.0.js:11634:24)
at Scope.$delegate.__proto__.$apply (<anonymous>:855:30)
The service I am testing:
angular.module('services.field', [])
.factory('Field', ['$http', '$cacheFactory', function ($http, $cacheFactory) {
var fieldListCache = $cacheFactory('fieldList');
var Field = function (data) {
angular.extend(this, data);
};
// add static method to retrieve all fields
Field.query = function () {
return $http.get('api/ParamSetting', {cache:fieldListCache}).then(function (response) {
var fields = [];
angular.forEach(response.data, function (data) {
fields.push(new Field(data));
});
return fields;
});
};
// add static method to retrieve Field by id
Field.get = function (id) {
return $http.get('api/ParamSetting/' + id).then(function (response) {
return new Field(response.data);
});
};
// add static method to save Field
Field.prototype.save = function () {
fieldListCache.removeAll();
var field = this;
return $http.post('api/ParamSetting', field ).then(function (response) {
field.Id = response.data.d;
return field;
});
};
return Field;
}]);
The unit test that is failing:
'use strict';
describe('Field service', function() {
var Field, $httpBackend;
// load the service module
beforeEach(module('services.field'));
// instantiate service
beforeEach(inject(function(_Field_, _$httpBackend_) {
Field = _Field_;
$httpBackend = _$httpBackend_;
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
describe("save()", function() {
it('should clear field array from cache', function () {
var firstMockData = [{ Alias: 'Alias 1' }, { Alias: 'Alias 2' }];
var secondMockData = [{ Alias: 'Alias 3' }];
var newField = new Field({});
var counter = 0;
$httpBackend.when('GET', 'api/ParamSetting').respond(function () {
// return firstMockData on first request and secondMockdata on subsequent requests
if (counter === 0) {
counter++;
return [200, firstMockData, {}];
} else {
return [200, secondMockData, {}];
}
});
$httpBackend.when('POST', 'api/ParamSetting').respond({});
// query fields
Field.query();
// save new field
newField.save();
// query fields again
Field.query().then(function (data) {
expect(data.length).toBe(secondMockData.length);
expect(data[0].Alias).toBe(secondMockData[0].Alias);
});
$httpBackend.flush();
});
});
});
回答1:
The answer is that I am erroneously expecting asynchronyous requests to return responses in a particular order, and that my requests are cached until I call $httpBackend.flush() which would lead to .query() only being called once. To make it work, one can make the calls synchronous by adding another flush after the first query() call: http://plnkr.co/edit/MzuplQnkQunDyvy6vCvy?p=preview
回答2:
The following code will allow you to mock out the $cacheFactory in your unit tests. The $provide service will allow the service dependency injection to use your $cacheFactory instead of the default $cacheFactory.
var cache, $cacheFactory; //used in your its
beforeEach(function(){
module(function ($provide) {
$cacheFactory = function(){};
$cacheFactory.get = function(){};
cache = {
removeAll: function (){}
};
spyOn(cache, 'removeAll');
spyOn($cacheFactory, 'get').and.returnValue(cache);
$provide.value('$cacheFactory', $cacheFactory);
});
});
describe('yourFunction', function(){
it('calls cache.remove()', function(){
yourService.yourFunction();
expect(cache.remove).toHaveBeenCalled();
});
});
来源:https://stackoverflow.com/questions/19966267/unit-test-of-cachefactory-removeall-in-service-failing-in-angular-1-2-0-but-w