【问题标题】:Unit Testing angular $httpBackend service单元测试角度 $httpBackend 服务
【发布时间】:2016-06-30 18:23:52
【问题描述】:

我现在有一个项目,我们需要暂时模拟后端服务器,并且我们在应用程序 .run 功能上使用 $httpBackend。我需要对包含$httpBackend 的服务进行单元测试,因为我们将对我们将覆盖的服务器进行大量模拟调用。所以现在这就是我所拥有的。作为我的问题的前言,当我从一个简单页面上的控制器调用 mockDataService.getWorkflowTask 时,当前设置有效。

我的服务器更换服务:

angular.module('app').run(function ($httpBackend, $resource, FakeBackendService) {
    // TODO: add all necessary http intercepts.  
    $httpBackend.whenGET('JSON file').respond(function (method, url, data) {
        var request = new XMLHttpRequest();
        request.open('GET', url, false);
        request.send(null);
        return [request.status, request.response, {}];
    });
    $httpBackend.whenGET(/.*/).respond(function (method, url, data) {

        return [200, FakeBackendService.getWorkflowTasks(), {}];
    });
});

这里是FakeBackendService的服务:

(function () {
    'use strict';

    var injectParams = [];

    function service(lodash) {
        var vm = this;

        var ret = {
            getWorkflowTasks: getWorkflowTasks
        };

        function getWorkflowTasks() {
            if (vm.workflowtasks.length < 1) {
                vm.workflowtasks = loadWorkflowTasks("Some JSON file");
            }
            return vm.workflowtasks;
        };

        function loadWorkflowTasks(file) {
            var workflowTasks = [];
            var request = new XMLHttpRequest();
            request.open("GET", file, false);
            request.send(null);

            if (request.status == 200) {
                workflowTasks = angular.fromJson(request.response);
            }
            return workflowTasks;
        };

        function init() {
            vm.workflowtasks = [];
        }

        init();

        return ret;
    }

    service.$inject = injectParams;
    angular.module('mock.FakeBackendService', []).service('FakeBackendService', service);
})();

所以这是当前后端服务器替换模拟。以下是我的数据处理服务,其中包含对$http.get(blah blah blah) 的调用。

(function () {
    'use strict';

    var injectParams = ['$http', '$q', 'mockConfigService', '$httpBackend'];

    function factory($http, $q, configService, $httpBackend) {
        var vm = this;

        var factory = {
            getWorkflowTask: getWorkflowTask
        };

        function getWorkflowTask(str) {
            return getResource(str);
        }

        function init() {
            // Get the URL we will be using to get data from
            vm.dataServiceURL = configService.getDataServiceURL();
        }

        function getResource(baseResource) {
            var resource = vm.dataServiceURL + baseResource;

            return $http.get(resource).then(function (response) {
                if (typeof response.data == 'object') {
                    // Got valid response
                    return $q.resolve(response.data);
                }
                else {
                    // Invalid response
                    return $q.reject(response.data);
                }
            }, function (response) {
                // Something went wrong
                return $q.reject(response.data);
            });
        }
        init();

        return factory;
    };

    factory.$inject = injectParams;

    angular.module('mock.dataService', []).factory('mockDataService', factory);
}());

现在是 Jasmine-Karma 单元测试。

describe("HTTP Backend Mock testing", function () {

    beforeEach(angular.mock.module("app"));
    beforeEach(angular.mock.module("mock.FakeBackendService"));
    beforeEach(angular.mock.module("mock.configService"));
    beforeEach(angular.mock.module("mock.dataService"));

    it("Get the workflow task", angular.mock.inject(function (mockDataService) {
        var valid = "";

        var promise = mockDataService.getWorkflowTask('http://localhost/foo');

        promise.then(function (response) {
            valid = "Success";
        }, function (response) {
            valid = "Failure";
        });

        expect(valid).toBe("Success");
    }));
});

现在回答问题。所以,我首先要说我是 AngularJS 世界的新手,对 Jasmine 更是如此。无论如何,当我调试单元测试时,我发现承诺的状态仍然是 0,我总是期望“成功”告诉我我永远不会解决(希望我使用正确的术语)来自 @987654331 的承诺@服务在mockDataService。我已经尝试过使用它,并试图看看是否有人以前做过这种事情。我发现了很多在测试中模拟 $httpBackend 的例子,但没有一个像我正在尝试的那样。任何想法或建议都会很棒。谢谢。

EDIT 得到了一个稍微可行的解决方案

所以我决定绕过run() 服务并在expectGET().respond() 中执行相同的响应。

describe("HTTP Backend Mock testing", function () {
    beforeEach(angular.mock.module("app"));
    beforeEach(angular.mock.module("mock.FakeBackendService"));
    beforeEach(angular.mock.module("mock.configService"));
    beforeEach(angular.mock.module("mock.dataService"));

    it("Get the workflow task", angular.mock.inject(function (mockDataService, $httpBackend, FakeBackendService) {
        var valid = "";
        $httpBackend.expectGET('http://server:80/api/foo').respond(200, FakeBackendService.getWorkflowTasks());
        var promise = mockDataService.getWorkflowTask('foo');


        promise.then(function (response) {
            valid = "Success";
        }, function (response) {
            valid = "Failure";
        });
        $httpBackend.flush();

        expect(valid).toBe("Success");
    }));
});

这解决了我使用run() 的测试问题,因为目标是验证1) 正则表达式匹配调用正确的FakeBackendService2) FakeBackendService 返回正确的文件并实际加载它。我想我可以通过模仿expectGET 中的相同正则表达式来做到这一点。但是,我会稍微开放一下,看看是否有人知道如何让run() 工作。

【问题讨论】:

    标签: angularjs unit-testing jasmine karma-jasmine


    【解决方案1】:

    除非您在测试结束前强制它这样做,否则 Promise 不会解决。这是一种这样的方法:

        $httpBackend.expectGET(......).respond(200, 'abc');
    
        var promise = mockDataService.getWorkflowTask('http://localhost/foo');
    
        promise.then(function (response) {
            valid = "Success";
        }, function (response) {
            valid = "Failure";
        });
    
        //new code here
        $httpBackend.flush();
    
        expect(valid).toBe("Success");
    

    这将强制 promise 解决并且您的测试应该通过。您还需要将 $httpBackend 服务注入到测试中。

    【讨论】:

    • 我试过了,我得到错误:意外的请求:GET blah blah blah 没有更多的请求预期
    • progress... 现在在你调用 mockDataService.getWorkflowTask(.....) 之前放一个 $httpBackend.expectGET(blah blah blah);
    • 我很感激奥斯汀,我试过了,但我得到了错误:没有定义响应!
    • $httpBackend.expectGET(blah blah blah).respond(200, {response: 'object'});
    • 然后从测试中删除 $httpbackend 东西
    【解决方案2】:

    angular.module('mock.dataService', [])
      .service('mockDataService', function($http) {
        this.getWorkflowTask = function(url) {
          return $http.get(url)
        }
      })
    
    describe('HTTP Backend Mock testing', function() {
      var $httpBackend
      beforeEach(angular.mock.module("mock.dataService"));
      beforeEach(inject(function(_$httpBackend_) {
        $httpBackend = _$httpBackend_
      }))
    
      it("Get the workflow task", angular.mock.inject(function(mockDataService) {
        $httpBackend.expectGET('http://localhost/foo').respond(200);
    
        var promise = mockDataService.getWorkflowTask('http://localhost/foo');
    
        promise.then(function(response) {
          valid = "Success";
        }, function(response) {
          valid = "Failure";
        });
    
        $httpBackend.flush();
    
        expect(valid).toBe("Success");
      }));
    })
    <link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
    <script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-mocks.js"></script>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-29
      • 1970-01-01
      • 2018-01-18
      • 2020-07-10
      • 2014-08-20
      • 2015-10-17
      相关资源
      最近更新 更多