javascript 测试我的 AngularJS 控制器时,如何在 $http.get 承诺中模拟结果?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17825798/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I mock the result in a $http.get promise when testing my AngularJS controller?
提问by Mendhak
After much reading, it seems that the recommended way to call a web service from an AngularJS controller is to use a factory and return a promise from that.
经过大量阅读,从 AngularJS 控制器调用 Web 服务的推荐方法似乎是使用工厂并从中返回承诺。
Here I have a simple factory which calls a sample API.
在这里,我有一个调用示例 API 的简单工厂。
myApp.factory('MyFactory', ['$http',function($http) {
var people = {
requestPeople: function(x) {
var url = 'js/test.json';
return $http.get(url);
}
};
return people;
}]);
And this is how I call it in the controller
这就是我在控制器中调用它的方式
myApp.controller('MyCtrl1', ['$scope', 'MyFactory', function ($scope, MyFactory) {
MyFactory.requestPeople(22).then(function(result) {
$scope.peopleList = result;
});
}]);
While it works fine, I would like to be able to mock the result
that is passed in when then
is called. Is this possible?
虽然它工作正常,但我希望能够模拟调用result
时传入的then
。这可能吗?
My attempt so far has produced nothing. This is my attempt:
到目前为止,我的尝试没有产生任何结果。这是我的尝试:
//Fake service
var mockService = {
requestPeople: function () {
return {
then: function () {
return {"one":"three"};
}
}
}
};
//Some setup
beforeEach(module('myApp.controllers'));
var ctrl, scope;
beforeEach(inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
ctrl = $controller('MyCtrl1', { $scope: scope, MyFactory: mockService });
}));
//Test
it('Event Types Empty should default to false', inject(function () {
expect(scope.peopleList.one).toBe('three');
}));
The error that I get when running this in karma runner, is
我在 karma runner 中运行时得到的错误是
TypeError: 'undefined' is not an object (evaluating 'scope.peopleList.one')
类型错误:'undefined' 不是一个对象(评估 'scope.peopleList.one')
How can I get this test working with my mocked data?
我怎样才能让这个测试与我的模拟数据一起工作?
回答by GogLlundain
I don't think $httpBackend is what you're after here, you want the whole factory to be mocked without it having a dependency on $http?
我不认为 $httpBackend 是您在这里所追求的,您希望整个工厂在不依赖于 $http 的情况下被模拟?
Take a look at $q, in particular the code sample under the Testing header. Your issue might be resolved with code that looks like this:
看看$q,特别是测试标题下的代码示例。您的问题可能会通过如下所示的代码解决:
'use strict';
describe('mocking the factory response', function () {
beforeEach(module('myApp.controllers'));
var scope, fakeFactory, controller, q, deferred;
//Prepare the fake factory
beforeEach(function () {
fakeFactory = {
requestPeople: function () {
deferred = q.defer();
// Place the fake return object here
deferred.resolve({ "one": "three" });
return deferred.promise;
}
};
spyOn(fakeFactory, 'requestPeople').andCallThrough();
});
//Inject fake factory into controller
beforeEach(inject(function ($rootScope, $controller, $q) {
scope = $rootScope.$new();
q = $q;
controller = $controller('MyCtrl1', { $scope: scope, MyFactory: fakeFactory });
}));
it('The peopleList object is not defined yet', function () {
// Before $apply is called the promise hasn't resolved
expect(scope.peopleList).not.toBeDefined();
});
it('Applying the scope causes it to be defined', function () {
// This propagates the changes to the models
// This happens itself when you're on a web page, but not in a unit test framework
scope.$apply();
expect(scope.peopleList).toBeDefined();
});
it('Ensure that the method was invoked', function () {
scope.$apply();
expect(fakeFactory.requestPeople).toHaveBeenCalled();
});
it('Check the value returned', function () {
scope.$apply();
expect(scope.peopleList).toBe({ "one": "three" });
});
});
I've added some tests around what $apply does, I didn't know that until I started playing with this!
我已经添加了一些关于 $apply 功能的测试,直到我开始玩这个我才知道!
Gog
高格