我想测试一个运行$ resource的工厂方法。我的测试会嘲笑那个尚不存在的真实后端。
以下是工厂代码示例:
app.factory( 'Global', function( $resource ){
var Jogas = $resource('/jogasok/:id', {'id': '@id'}, {
'ujBerlet': {'method': 'POST', 'params': {'berlet': true}}
});
var jogasok = Jogas.query();
return {
getJogasok: function() {
return jogasok;
}
};
})
我的测试是检查查询是否已经完成。
如果我用以下内容初始化我的应用程序:
app.run( function run ($httpBackend) {
$httpBackend.whenGET('/jogasok').respond([
{id: 1, name: 'asdfasdf'},
{id: 2, name: '2wrerwert'}
]);
})
并在我的浏览器中打开应用程序,然后一切似乎都很好,我在浏览器中有虚拟数据。
但是,当我拿出上面的运行代码并编写测试时,事情就不起作用了。
describe( 'Global Service: ', function() {
beforeEach( module('bkJoga') );
beforeEach( inject(function($httpBackend) {
$httpBackend.whenGET('/jogasok').respond([
{id: 1, name: 'asdfasdf'},
{id: 2, name: '2wrerwert'}
]);
}));
it('getJogasok should return everyone', inject(function(Global) {
expect(JSON.stringify(Global.getJogasok())).toBe(JSON.stringify([
{id: 1, name: 'asdfasdf'},
{id: 2, name: '2wrerwert'}
]));
}));
});
失败。
答案 0 :(得分:5)
这是您发布工厂时的工作测试。我为注入的httpBackend添加了一个变量$ httpBackend。并调用$ httpBackend.flush()。 fiddle-demo (阅读结尾以获取小提琴内容的完整描述)
describe( 'Global Service: ', function() {
var Global, $httpBackend
// load the relevant application module, with the service to be tested
beforeEach( module('bkJoga') );
beforeEach( function() {
// inject the mock for the http backend
inject(function(_$httpBackend_) {
$httpBackend = _$httpBackend_;
});
// mock the response to a particular get request
$httpBackend.whenGET('/jogasok').respond([
{id: 1, name: 'asdfasdf'},
{id: 2, name: '2wrerwert'}
]);
// inject the service to be tested
inject(function(_Global_) {
Global = _Global_;
});
});
it('should exist', function() {
expect(!!Global).toBe(true);
});
it('getJogasok should return everyone', function() {
$httpBackend.flush(); // <------------ need to flush $httpBackend
expect(JSON.stringify(Global.getJogasok())).toBe(JSON.stringify([
{id: 1, name: 'asdfasdf'},
{id: 2, name: '2wrerwert'}
]));
});
});
无论如何,我会以不同的方式重写工厂,因为,正如当前编写的那样,它仅在实例化var jogasok = Jogas.query();
时才查询数据库。因为services in angularjs are singletons,在您的应用中,您将只拥有实例化时的数据。因此,以后对数据的修改不会反映在您的工厂中。
以下是反映这一想法的工厂及其单元测试的示例。
工厂:
app.factory('GlobalBest', function ($resource) {
return $resource('/jogasok/:id', {
'id': '@id'
}, {
'ujBerlet': {
'method': 'POST',
'params': {
'berlet': true
}
}
});
});
测试:
describe('GlobalBest Service: ', function () {
var srv, $httpBackend;
beforeEach(module('bkJoga'));
beforeEach(function () {
// inject the mock for the http backend
inject(function (_$httpBackend_) {
$httpBackend = _$httpBackend_;
});
// inject the service to be tested
inject(function (_GlobalBest_) {
srv = _GlobalBest_;
});
});
it('should exist', function () {
expect( !! srv).toBe(true);
});
it('query() should return everyone', function () {
// mock the response to a particular get request
$httpBackend.whenGET('/jogasok').respond([{
id: 1,
name: 'asdfasdf'
}, {
id: 2,
name: '2wrerwert'
}]);
// send request to get everyone
var data = srv.query();
// flush the pending request
$httpBackend.flush();
expect(JSON.stringify(data)).toBe(JSON.stringify([{
id: 1,
name: 'asdfasdf'
}, {
id: 2,
name: '2wrerwert'
}]));
});
it('get({id: 1}) should return object with id=1', function () {
// mock the response to a particular get request
$httpBackend.whenGET('/jogasok/1').respond({
id: 1,
name: 'asdfasdf'
});
var datum = srv.get({
id: 1
});
$httpBackend.flush();
expect(JSON.stringify(datum)).toBe(JSON.stringify({
id: 1,
name: 'asdfasdf'
}));
});
});
我写了一个带有3个版本服务的 fiddle-demo :你的原始服务'Global',一个返回query()方法的新版本'GlobalNew',最后是一个版本“GlobalBest”直接返回$资源。希望这会有所帮助。
答案 1 :(得分:2)
尝试将其从.toBe
更改为.toEqual
。 Jasmine使用toBe
对象引用相等,并与toEqual
进行深度比较。
答案 2 :(得分:1)
到目前为止,我能得到的最佳答案是创建另一个应用程序,继承我的应用程序+使用ngMockE2E服务。这样就可以模拟出这些请求。
注意:遗憾的是,我无法使用我的测试环境
答案 3 :(得分:0)
使用angular.mock.inject
创建模拟服务的实例,然后需要调用模拟flush()
的{{1}},这允许测试显式刷新挂起的请求,从而保留后端的异步api,同时允许测试同步执行。
$httpBackend
的 Demo 强>
答案 4 :(得分:0)
关于AngularJS测试的一篇很好的文章也涉及到后端模拟:http://nathanleclaire.com/blog/2013/12/13/how-to-unit-test-controllers-in-angularjs-without-setting-your-hair-on-fire/