问题描述
我已经看了好几个小时了.我已经尝试了一个又一个例子.我似乎无法让它发挥作用.请帮忙=)
I've been looking at this for hours. I've tried example after example. I just can't seem to get this to work. Please help =)
我在 angular-seed repo (git://github.com/angular/angular-seed.git) 的干净克隆上做这一切.除了下面列出的之外,我没有进行任何更改.
I am doing all this on a clean clone of the angular-seed repo (git://github.com/angular/angular-seed.git). I have made no changes except those listed below.
当我运行以下命令时,测试有效.请注意,在此版本中,服务在执行任何类型的 $http 调用之前都会返回一个值.
When I run the following, the test works. Note that in this version, the service returns a value before doing any kind of $http call.
./app/js/services/services.js
'use strict';
angular.module('myApp.services', [])
.factory("exampleService", function ($http) {
return {value:"goodValue"};
$http.get("/exampleUrl")
.success(function () {
return {value:"goodValue"};
})
.error(function () {
return {value:"badValue"};
})
});
./test/unit/servicesSpec.js
'use strict';
describe('service', function() {
var $httpBackend;
beforeEach(module('myApp.services'));
beforeEach(inject(function ($injector) {
$httpBackend = $injector.get("$httpBackend");
$httpBackend.when("GET", "/exampleUrl")
.respond({value:"goodValue"});
}));
afterEach(function () {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
describe('exampleService', function () {
it('.value should be "goodValue"', inject(function (exampleService) {
expect(exampleService.value).toEqual("goodValue");
}));
});
});
结果
info (watcher): Changed file "/home/username/mocktest/test/unit/servicesSpec.js".
Chrome 26.0: Executed 5 of 5 SUCCESS (0.136 secs / 0.035 secs)
当我删除行 return {value:"goodValue"};
并实际让它运行 $http.get()
时,整个事情都与以下错误:
When I remove the line return {value:"goodValue"};
and actually let it run the $http.get()
, the whole thing breaks with the following errors:
info (watcher): Changed file "/home/username/mocktest/app/js/services.js".
Chrome 26.0 service exampleService .value should be "goodValue" FAILED
TypeError: Cannot read property 'value' of undefined
at null.<anonymous> (/home/username/mocktest/test/unit/servicesSpec.js:22:28)
at Object.invoke (/home/username/mocktest/app/lib/angular/angular.js:2864:28)
at workFn (/home/username/mocktest/test/lib/angular/angular-mocks.js:1758:20)
Error: Declaration Location
at window.jasmine.window.inject.angular.mock.inject (/home/username/mocktest/test/lib/angular/angular-mocks.js:1744:25)
at null.<anonymous> (/home/username/mocktest/test/unit/servicesSpec.js:21:40)
at null.<anonymous> (/home/username/mocktest/test/unit/servicesSpec.js:20:3)
at /home/username/mocktest/test/unit/servicesSpec.js:4:1
Error: Unflushed requests: 1
at Error (<anonymous>)
at Function.$httpBackend.verifyNoOutstandingRequest (/home/username/mocktest/test/lib/angular/angular-mocks.js:1225:13)
at null.<anonymous> (/home/username/mocktest/test/unit/servicesSpec.js:17:18)
Chrome 26.0: Executed 5 of 5 (1 FAILED) (0.14 secs / 0.043 secs)
想法
我怀疑我需要在服务中返回某种承诺对象,然后解决它,但我不知道那会是什么.任何帮助表示赞赏.
Thoughts
I suspect I need to do some kind of returning of a promise object in the service, then resolve it afterwards, but I have no idea what that would be. Any help appreciated.
推荐答案
你怀疑的解决方案是在正确的轨道上 - 承诺是修复错误/失败测试的关键.
Your suspected solution was on the right track - promises were the key to fixing the errors/failing tests.
使用您原来的 $http
服务有条件地返回工厂对象不起作用,因为您实际上是从工厂函数返回 nothing (由于异步承诺解析$http
).
Using your original $http
service to conditionally return the factory object didn't work because you were effectively returning nothing from your factory function (due to the asynchronous promise resolution of $http
).
我考虑将 return
放在您原来的 $http.get()
调用之前.但这不是期望的行为,因为 AngularJS .factory
方法应该返回一个您定义的服务对象,而不仅仅是调用 $http
返回的承诺.
I considered just putting return
in front of your original $http.get()
call. But that isn't the desired behavior, because the AngularJS .factory
method should return a service object that you define, not an mere promise returned by the call to $http
.
解决方案是在您的 exampleService
对象上公开一个可由您的应用调用的方法.getData()
方法返回一个承诺(通过 $http
),您的应用/测试可以使用 .success()
或 异步处理该承诺>.error()
The solution is exposing a method on your exampleService
object that can be called by your app. That getData()
method returns a promise (via $http
) which your app/test can handle asynchronously using .success()
or .error()
./app/js/services/services.js
'use strict';
angular.module('myApp.services', [])
.factory("exampleService", function ($http) {
return {
getData: function () {
return $http.get("/exampleUrl");
}
}
});
./test/unit/servicesSpec.js
'use strict';
describe('service', function() {
var $httpBackend;
beforeEach(module('myApp.services'));
beforeEach(inject(function ($injector) {
$httpBackend = $injector.get("$httpBackend");
$httpBackend.when("GET", "/exampleUrl")
.respond(200, {value:"goodValue"});
}));
afterEach(function () {
$httpBackend.flush()
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
describe('exampleService successful http request', function () {
it('.value should be "goodValue"', inject(function (exampleService) {
exampleService.getData().success(function(response) {
expect(response.value).toEqual("goodValue");
}).error( function(response) {
//should not error with $httpBackend interceptor 200 status
expect(false).toEqual(true);
});
}));
});
});
请注意,Destron 关于 $httpBackend.flush()
的评论对于让模拟后端拦截来自您的服务的 $http.get()
请求也很重要.
Note that Destron's comment about $httpBackend.flush()
was also important to get the mock backend to intercept the $http.get()
request from your service.
希望对您有所帮助.
这篇关于使用 ngMock 模拟服务单元测试中的 $http 调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!