如何在$http中模拟结果。当测试我的AngularJS控制器时得到承诺?

时间:2023-01-29 21:13:08

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?

虽然它运行良好,但我希望能够模拟调用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

在《因果报应》中运行时,我得到的错误是

TypeError: 'undefined' is not an object (evaluating 'scope.peopleList.one')

TypeError: 'undefined'不是对象(评估'scope.people .one')

How can I get this test working with my mocked data?

如何使用我的模拟数据进行测试?

1 个解决方案

#1


38  

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?

我不认为$http后端是你想要的,你想让整个工厂被嘲笑而不依赖于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!

我添加了一些关于应用程序的测试,我不知道,直到我开始玩这个!

Gog

高格

#1


38  

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?

我不认为$http后端是你想要的,你想让整个工厂被嘲笑而不依赖于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!

我添加了一些关于应用程序的测试,我不知道,直到我开始玩这个!

Gog

高格