0

在弄清楚如何在工厂测试 $http 请求时遇到问题。

基础工厂:

angular.module('myServices', [])
    .factory('myFactory', function($http) {
        return {
            postLog: function(logData) {
                logData.newProperty = 'my new property';
                return $http.post('/log', logData);
            };
        };
    });

现在我想测试一下以确保我添加了我的newProperty. 我希望能够编写如下测试:

it('adds a new property before POSTing', function() {
    MyFactory.postLog({message: 'posting a log!'});
    // catch the request somehow
    expect(theRequest.data).to.have.property('newProperty');
});

我最初的想法是这样$httpBackend.expect可以让我访问请求,但它似乎只有一个.respond方法,没有别的:

var MyFactory, backend;

beforeEach(function() {
    module('exampleApp');

    inject(function($httpBackend, _myFactory_) {
        backend = $httpBackend;
        backend.expect('POST', '/log').???  // would be nice to have a `.request` method here or a parameter passed to `.respond`
        MyFactory = _myFactory_;
    });

});

所以我尝试httpInterceptor通过执行以下操作来设置:

var MyFactory, theRequest;

beforeEach(function() {
    module('exampleApp', function($provide, $httpProvider) {
        $provide.service('requestCatcher', function() {
            this.request = function(req) {
                console.log(req);
                request = req;

                return req;
            };
        });

        $httpProvider.interceptors.push('requestCatcher');
    });

    inject(function(_myFactory_) {
        MyFactory = _myFactory_;
    });
});

it('adds a new property before POSTing', function() {
    MyFactory.postLog({message: 'posting a log!'});
    expect(theRequest.data).to.have.property('newProperty');
});

但拦截器从未真正触发(日志不会打印到日志中)。我对这个有点想法。

也许我在postLog方法中添加新属性违反了某些原则,应该将其重构为自己的可测试性方法?尽管如此,如果有一种方法可以利用出站请求,即使它会被$httpBackend.expect.

4

2 回答 2

0

您走在正确的轨道上,但是您应该在函数中创建模拟以beforeEach()实现多功能性。

describe('MyFactory', function() {
    var $httpBackend, userMock, MyFactory;

    beforeEach(inject(function(_$httpBackend_, _MyFactory_) {
        $httpBackend = _$httpBackend_;
        MyFactory = _MyFactory_;

        userMock = {user: {id: 1, name: 'shy guy'}};
    }));

    it('should pass', function() {
       $httpBackend.expectGET('/api/path/to/your/endpoint').respond(userMock);

       MyFactory.postLog({message: 'whatever'});
       $httpBackend.flush(); // Will dump the test data from the endpoint we specified above.

       expect(true).toBe(true);
    });
});

这里发生了什么?

  • expectGET当您指定的 url 在测试中被调用时准备响应数据。

  • flush()是响应数据被转储的触发器(因为在某些情况下时间可以是一切)。

请注意,如果您调用expectGET但实际上并未向指定的 url 发出请求,则测试将失败。

继续测试!超级值得:)

于 2015-03-27T01:01:57.790 回答
0

感谢 Angularjs gitter.im 上的优秀人员:

$httpBackend.expect('POST', '/log').respond(function(method, url, data, headers) {
   var mockReturnData = [{...}, {...}];
   console.log(data); // this is the data that was sent to the endpoint
   return [200, mockReturnData];
});

在任何地方的文档中都找不到这个

于 2015-03-27T00:38:02.790 回答