【发布时间】:2014-03-12 15:44:01
【问题描述】:
我目前正在使用karma 和jasmine 为某些服务编写测试,我想知道是否必须模拟使用$http 的服务的服务依赖项,如下所述。
PS:我已经在使用 $httpBackend 模拟任何 GET 请求,如果我不模拟服务 ApiProvider,我计划使用 $httpBackend.expect*
这是我正在测试的服务
.factory('CRUDService', ['ApiProvider', function (ApiProvider) {
'use strict';
var CRUD = function CRUD(modelName) {
this.getModelName = function () {
return modelName;
};
},
overridableMethods = {
save: null
};
CRUD.prototype = {
save: function () {
// ABSTRACT
},
/**
* Deletes instance from id property
* @return http promise
*/
remove: function () {
return ApiProvider.delete(this.getModelName(), this.id);
}
};
return {
/**
* Function creating a class extending CRUD
* @param {string} modelName
* @param {Object} methods an object with methods to override, ex: save
* return {classD} the extended class
*/
build: function (modelName, methods) {
var key,
Model = function () {
};
// Class extending CRUD
Model.prototype = new CRUD(modelName);
// Apply override on methods allowed for override
for (key in methods) {
if (key in overridableMethods &&
typeof methods[key] === 'function') {
Model.prototype[key] = methods[key];
}
}
/**
* Static method
* Gets an entity of a model
* @param {Object} config @see ApiProvider config
* @return {CRUD} the reference to the entity
*/
Model.get = function (config, success) {
var entity = new Model();
ApiProvider.get(modelName, config)
.success(function (data) {
angular.extend(entity, data);
if (success) {
success();
}
});
return entity;
};
/**
* Static method
* Gets entities of a model
* @param {Object} config @see ApiProvider config
* @return {CRUD[]} the reference to the entity
*/
Model.query = function (config, success) {
var entities = [];
ApiProvider.get(modelName, config)
.success(function (data) {
data.map(function (model) {
var entity = new Model();
angular.extend(entity, model);
return entity;
});
Array.prototype.push.apply(entities, data);
if (success) {
success();
}
});
return entities;
};
return Model;
},
// Direct link to ApiProvider.post method
post: ApiProvider.post,
// Direct link to ApiProvider.put method
put: ApiProvider.put
};
}]);
这是服务的服务依赖ApiProvider
.service('ApiProvider', function ($http) {
/**
* Private
* @param {string}
* @param {object}
* @return {string} Example: /service/[config.id[/config.relatedModel], /?config.params.key1=config.params.value1&config.params.key2=config.params.value2]
*/
var buildUrl = function (service, config) {
var push = Array.prototype.push,
url = [apiRoot, service],
params = [],
param = null;
// if a key id is defined, we want to target a specific resource
if ('id' in config) {
push.apply(url, ['/', config.id]);
// a related model might be defined for this specific resource
if ('relatedModel' in config) {
push.apply(url, ['/', config.relatedModel]);
}
}
// Build query string parameters
// Please note that you can use both an array or a string for each param
// Example as an array:
// {
// queryString: {
// fields: ['field1', 'field2']
// }
// }
// Example as a string
// {
// queryString: {
// fields: 'field1,field2'
// }
// }
if ('queryString' in config) {
// loop through each key in config.params
for (paramName in config.queryString) {
// this gives us something like [my_key]=[my_value]
// and we push that string in params array
push.call(params, [paramName, '=', config.queryString[paramName]].join(''));
}
// now that all params are in an array we glue it to separate them
// so that it looks like
// ?[my_first_key]=[my_first_value]&[my_second_key]=[my_second_value]
push.apply(url, ['?', params.join('&')]);
}
return url.join('');
},
request = function (method, url, methodSpecificArgs) {
trace({
method: method,
url: url,
methodSpecificArgs: methodSpecificArgs
}, 'ApiProvider request');
return $http[method].apply($http, [url].concat(methodSpecificArgs));
},
methods = {
'get': function (url, config) {
config.cache = false;
return request('get', url, [config]);
},
'post': function (url, data, config) {
config.cache = false;
return request('post', url, [data, config]);
},
'put': function (url, data, config) {
config.cache = false;
return request('put', url, [data, config]);
},
'delete': function (url, config) {
config.cache = false;
return request('delete', url, [config]);
}
};
return {
'get': function (service, config) {
config = config || {};
return methods.get(buildUrl(service, config), config);
},
'post': function (service, data, config) {
config = config || {};
return methods.post(buildUrl(service, config), data, config);
},
'put': function (service, data, config) {
config = config || {};
return methods.put(buildUrl(service, config), data, config);
},
'delete': function (service, config) {
config = config || {};
return methods.delete(buildUrl(service, config), config);
}
};
});
这就是我迄今为止测试 CRUDService 的方式
describe('CRUDServiceTest', function () {
'use strict';
var CRUDService;
beforeEach(function () {
inject(function ($injector) {
CRUDService = $injector.get('CRUDService');
});
});
it('should have a method build', function () {
expect(CRUDService).toHaveMethod('build');
});
it('should ensure that an instance of a built service has a correct value for getModelName method',
function () {
var expectedModelName = 'myService',
BuiltService = CRUDService.build(expectedModelName),
instanceOfBuiltService = new BuiltService();
expect(instanceOfBuiltService).toHaveMethod('getModelName');
expect(instanceOfBuiltService.getModelName()).toEqual(expectedModelName);
});
// TEST get
it('should ensure build returns a class with static method get', function () {
expect(CRUDService.build()).toHaveMethod('get');
});
it('should ensure get returns an instance of CRUD', function() {
var BuiltService = CRUDService.build(),
instanceOfBuiltService = new BuiltService();
expect((BuiltService.get()).constructor).toBe(instanceOfBuiltService.constructor);
});
// TEST query
it('should ensure build returns a class with static method query', function () {
expect(CRUDService.build()).toHaveMethod('query');
});
it('should a collection of CRUD', function () {
expect(CRUDService.build()).toHaveMethod('query');
});
it('should have a static method post', function () {
expect(CRUDService).toHaveMethod('post');
});
it('should have a static method put', function () {
expect(CRUDService).toHaveMethod('put');
});
});
TLDR;
根据 $http 模拟或不模拟依赖服务?
【问题讨论】:
标签: javascript angularjs unit-testing mocking jasmine