【问题标题】:AngularJS Testing and $httpAngularJS 测试和 $http
【发布时间】:2016-02-03 15:38:59
【问题描述】:

所以我试图弄清楚如何为我的角度控制器编写单元测试。我正在使用业力作为我的跑步者。我能够编写 1 个成功的测试,但每次我尝试编写另一个测试时,它都会对我大喊意外的电话等。

这是我正在尝试测试的控制器。

(function (angular) {
'use strict';
var ngModule = angular.module('myApp.dashboardCtrl', []);
ngModule.controller('dashboardCtrl', function ($scope, $http) {

    //"Global Variables"
    var vm = this;
    vm.success = false;
    vm.repos = [];

    //"Global Functions"
    vm.addRepository = addRepository;
    vm.listRepos = listRepos;

    //Anything that needs to be instantiated on page load goes in the init
    function init() {
        listRepos();
    }
    init();

    // Add a repository
    function addRepository(repoUrl) {
        $http.post("/api/repo/" + encodeURIComponent(repoUrl)).then(function (){
            vm.success = true;
            vm.addedRepo = vm.repoUrl;
            vm.repoUrl = '';
            listRepos();
        });
    }
    //Lists all repos
    function listRepos() {
        $http.get('/api/repo').then( function (response){
            vm.repos = response.data;

        });
    }
});
}(window.angular));

所以我为 listRepos() 编写了一个测试。如下

describe('dashboardCtrl', function() {
var scope, httpBackend, createController;
// Set up the module
beforeEach(module('myApp'));

beforeEach(inject(function($rootScope, $httpBackend, $controller) {
    httpBackend = $httpBackend;
    scope = $rootScope.$new();
    createController = function() {
        return $controller('dashboardCtrl', {
            '$scope': scope
        });
    };
}));

afterEach(function() {
    httpBackend.verifyNoOutstandingExpectation();
    httpBackend.verifyNoOutstandingRequest();
});

it('should call listRepos and return all repos from the database', function() {
    var controller = createController();
    var expectedResponse = [{id: 12345, url: "https://github.com/myuser/myrepo.git"}];

    httpBackend.expect('GET', '/api/repo')
        .respond(expectedResponse);
    httpBackend.flush();

    scope.$apply(function() {
        scope.listRepos;
    });

    expect(controller.repos).toEqual(expectedResponse);
});

这有效并且测试通过了。现在我的问题是我想编写另一个测试来测试另一个调用新 api 端点的函数。

这是我试图为 addRepository 编写的测试。

 it('should addRepository to the database', function() {
        var controller = createController();
        var givenURL = "https://github.com/myuser/myURLtoMyRepo.git";

        httpBackend.expect('POST', '/api/repo/' + encodeURIComponent(givenURL)).respond('success');
        httpBackend.flush();

        scope.$apply(function() {
            scope.addRepository(givenURL);
        });

        expect(controller.success).toBe(true);
        expect(controller.listRepos).toHaveBeenCalled();
    });

将此测试添加到规范时出现的错误是:

Error: Unexpected request: GET /api/repo
Expected POST /api/repo/https%3A%2F%2Fgithub.com%2Fmyuser%2FmyURLtoMyRepo.git
    at $httpBackend 
Error: [$rootScope:inprog] $digest already in progress
http://errors.angularjs.org/1.4.8/$rootScope/inprog?p0=%24digest

我正在使用的示例是this one here

非常感谢任何建议或提示!

更新:

所以更改了我的函数以从 $http.post 返回承诺,

我重写了我的第二个测试,并将我的第一个测试包装在一个描述它试图测试的函数的描述块中。

以下内容:

describe('addRepository', function () {

    it('should addRepository to the database', function () {
        var controller = createController();
        var givenURL = "https://github.com/myuser/myURLtoMyRepo.git";

        httpBackend.expect('POST', '/api/repo/' + encodeURIComponent(givenURL)).respond('success');

        scope.$apply(function () {
            scope.addRepository(givenURL);
        });
        httpBackend.flush();

        expect(controller.success).toBe(true);
    });
    it('should call listRepos', function() {
        var controller = createController();
        httpBackend.expect('GET', '/api/repo').respond('success');

        controller.controller().then(function (result) {
            expect(controller.listRepos).toHaveBeenCalled();

        });
        httpBackend.flush();
    });
});

我仍然收到错误:

Error: Unexpected request: GET /api/repo
Expected POST /api/repo/https%3A%2F%2Fgithub.com%2Fmyuser%2FmyURLtoMyRepo.git
    at $httpBackend 
Error: [$rootScope:inprog] $digest already in progress

还有

TypeError: 'undefined' is not a function (evaluating 'controller.controller()') 
Error: Unflushed requests: 1

显示 2 个测试失败。

【问题讨论】:

    标签: angularjs unit-testing jasmine karma-runner angular-mock


    【解决方案1】:

    flush 应该在函数调用之后出现。我还将更改函数以从$http.post 返回承诺:

        // Add a repository
        function addRepository(repoUrl) {
            return $http.post("/api/repo/" + encodeURIComponent(repoUrl)).then(function (){
                vm.success = true;
                vm.addedRepo = vm.repoUrl;
                vm.repoUrl = '';
                listRepos();
            });
        }
    

    然后在测试中可以调用它并测试成功部分:

    编辑

    我将controller.controller() 更改为您所拥有的。

    it('should call listRepos', function() {
        // Your setup
        ctrl.addRepository().then(function(result) {
            expect(ctrl.listRepos).toHaveBeenCalled();
        });
    });
    

    编辑 2

    我尽我所能模仿你的代码和我为代码编写的测试:

    (function () {
      'use strict';
    
      angular
        .module('myApp')
        .controller('DashboardController',DashboardController);
    
        DashboardController.$inject = ['$http'];
    
        function DashboardController($http) {
    
          var vm = this;
          vm.success = false;
          vm.repos = [];
    
          vm.addRepository = addRepository;
          vm.listRepos = listRepos;
    
          init();
    
          // Anything that needs to be instantiated on page load goes in the init
          function init() {
            vm.listRepos();
          } 
    
          // Add a repository
          function addRepository(repoUrl) {
            return $http.post('http://jsonplaceholder.typicode.com/posts/1.json').then(function (){
              vm.success = true;
              vm.addedRepo = vm.repoUrl;
              vm.repoUrl = '';
              vm.listRepos();
            });
          }
          // Lists all repos
          function listRepos() {
            return $http.get('http://jsonplaceholder.typicode.com/posts/1').then( function (response){
              vm.repos = response.data;
            });
          }
        };
    }());
    

    在这里,我使用在线 JSONPlaceholder API 来模拟 HTTP 调用,因为我显然无法点击您所指的内容。对于测试(全部通过):

    (function() {
        'use strict';
    
        fdescribe('DashBoardController', function() {
            var $rootScope, scope, ctrl, $httpBackend;
            beforeEach(module('myApp'));
    
            beforeEach(inject(function(_$rootScope_, _$httpBackend_,$controller) {
                $rootScope      = _$rootScope_; 
                scope           = $rootScope.$new();
                $httpBackend    =_$httpBackend_;
    
                ctrl = $controller('DashBoardController',{
                    $scope: scope
                });
            }));
    
            beforeEach(function() {
                // Setup spies
                spyOn(ctrl,'listRepos');
            });
    
            describe('controller', function() {
                it('should be defined', function() {
                    expect(ctrl).toBeDefined();
                });
                it('should initialize variables', function() {
                    expect(ctrl.success).toBe(false);
                    expect(ctrl.repos.length).toBe(0);
                });
            });
    
            describe('init', function() {
    
                it('should call listRepos', function() {
                    $httpBackend.expectGET('http://jsonplaceholder.typicode.com/posts/1')
                        .respond({success: '202'});
    
                    $httpBackend.expectPOST('http://jsonplaceholder.typicode.com/posts/1.json')
                        .respond({success: '202'});
    
                    ctrl.addRepository().then(function(result) {
                        expect(ctrl.success).toBe(true);
                        expect(ctrl.repoUrl).toBe('');
                        expect(ctrl.listRepos).toHaveBeenCalled();
                    });
    
                    $httpBackend.flush();
                });
            });
        });
    
    }()); 
    

    【讨论】:

    • 我试过了,看看我如何实现它的更新以及抛出的错误
    • 我能够摆脱意外的呼叫错误。现在我得到 TypeError: 'undefined' is not a function (evalating 'controller.controller()')
    • 停止调用你不需要的 $scope.$appy() - 这将摆脱一个错误。你为什么打电话给 controller.controller() - 我知道我把它放在我的代码中,但这只是一个例子 - 尽管名字不好。查看我的编辑
    • TypeError: 'undefined' is not an object (evalating 'controller.addRepository(givenURL).then') 错误: Unflushed requests: 1
    • 嗯 - 给我一点时间来模仿这个 - 它开始让我烦恼
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    • 1970-01-01
    • 1970-01-01
    • 2014-01-10
    • 2014-09-08
    • 2014-03-20
    • 1970-01-01
    相关资源
    最近更新 更多