如何在karma-jasmine中为AngularJS单元测试编写模拟

时间:2016-12-20 12:32:51

标签: angularjs unit-testing jasmine karma-jasmine

我必须对我的控制器进行单元测试。首先,我必须为我的服务创建模拟。

这是我的服务:

angular.module("demo-app")
.factory("empService",function($http){

    var empService={};
    empService.getAllEmployees=function(){
        return $http.get("http://localhost:3000/api/employees");
    }

    empService.postEmployee=function(emp){
        return $http.post("http://localhost:3000/api/employees",emp);
    }

    empService.getEmployee=function(id){
        return $http.get("http://localhost:3000/api/employees/"+id)
    }

    empService.putEmployee=function(emp){
        return $http.put("http://localhost:3000/api/employees/"+emp._id,emp)
    }

    empService.deleteEmployee=function(id){
        return $http.delete("http://localhost:3000/api/employees/"+id);
    }

    empService.findEmployee=function(emp){
        return $http.post("http://localhost:3000/api/employees/search",emp);
    }

    return empService;
})

这是我的控制器中的findData()方法,我将测试它:

$scope.findData=function(){
    $scope.loadingEmployee=true;
    var emp={};
    listProp=Object.getOwnPropertyNames($scope.searchEmployee);
    for(index in listProp){
        if($scope.searchEmployee[listProp[index]]!=""){
            emp[listProp[index]]=$scope.searchEmployee[listProp[index]];
        }
    }
    console.log(emp);
    empService.findEmployee(emp).then(function(data){   
        $scope.allEmployees=data.data;
        console.log(data.data);
        $scope.loadingEmployee=false;
    });
}

如何模拟我的empService.findEmployee(emp)方法,以便我可以测试findData()方法。

我的spec.js测试文件,模拟我的服务方法。这是:

beforeEach(function(){
    var emp={"name":"sanjit"};
    fakeService={
        getAllEmployees:function(emp){
            def=q.defer();
            def.resolve({data:[{"name":"sanjit"},{'name':'ssss'}]});
            return def.promise;
        },
        findEmployee:function(emp){
            var def=q.defer();
            def.resolve({data:[{"name":"sanjit"}]});
            console.log("working");
            return def.promise;
        }
    };
    spyOn(fakeService,'findEmployee').and.callThrough();
    fakeService.findEmployee(emp);
});
beforeEach(angular.mock.inject(function($rootScope,$controller,$injector,$q){
    httpBackend=$injector.get('$httpBackend');
    scope=$rootScope.$new();
    q=$q;
    ctrl=$controller('adminEmployeeCtrl',{$scope:scope,empService:fakeService});
})); 

it('findData test',function(){
    scope.$apply();
    scope.findData();
    expect(scope.loadingEmployee).toEqual(false);
})

但我又收到了一个错误:

 Error: Unexpected request: GET dashboard/views/dashboard-new.html
 No more request expected

但我没有打电话给它。请帮帮我

2 个答案:

答案 0 :(得分:1)

您可能没有手动调用GET dashboard/views/dashboard-new.html,但$scope.$apply()可能会以某种方式触发它,除了处理它之外您无法做任何事情。

您可以执行以下操作来处理它:(在使用_$httpBackend_注入并在$httpBackend中分配给beforeEach后)

$httpBackend.when('GET', 'dashboard/views/dashboard-new.html').respond(200);
scope.$digest();
$httpBackend.flush();

答案 1 :(得分:0)

在angularjs中测试控制器时,最重要的规则之一是您不需要创建重新发送http请求,只需模拟控制器使用的该服务中的函数。所以你需要窥探它们并调用假函数来返回正确的值。让他们中的一个间谍

/**
 * @description Tests for adminEmployeeCtrl controller
 */
(function () {

    "use strict";

    describe('Controller: adminEmployeeCtrl ', function () {

        /* jshint -W109 */
        var $q, $scope, $controller;
        var empService;
        var errorResponse = 'Not found';


        var employeesResponse = [
            {id:1,name:'mohammed' },
            {id:2,name:'ramadan' }
        ];

        beforeEach(module(
            'loadRequiredModules'
        ));

        beforeEach(inject(function (_$q_,
                                    _$controller_,
                                    _$rootScope_,
                                    _empService_) {
            $q = _$q_;
            $controller = _$controller_;
            $scope = _$rootScope_.$new();
            empService = _empService_;
        }));

        function successSpies(){

            spyOn(empService, 'findEmployee').and.callFake(function () {
                var deferred = $q.defer();
                deferred.resolve(employeesResponse);
                return deferred.promise;
                // shortcut can be one line
                // return $q.resolve(employeesResponse);
            });
        }

        function rejectedSpies(){
            spyOn(empService, 'findEmployee').and.callFake(function () {
                var deferred = $q.defer();
                deferred.reject(errorResponse);
                return deferred.promise;
                // shortcut can be one line
                // return $q.reject(errorResponse);
            });
        }

        function initController(){

            $controller('adminEmployeeCtrl', {
                $scope: $scope,
                empService: empService
            });
        }


        describe('Success controller initialization', function(){

            beforeEach(function(){

                successSpies();
                initController();
            });

            it('should findData by calling findEmployee',function(){
                $scope.findData();
                // calling $apply to resolve deferred promises we made in the spies
                $scope.$apply();
                expect($scope.loadingEmployee).toEqual(false);
                expect($scope.allEmployees).toEqual(employeesResponse);
            });
        });

        describe('handle controller initialization errors', function(){

            beforeEach(function(){

                rejectedSpies();
                initController();
            });

            it('should handle error when calling findEmployee', function(){
                $scope.findData();
                $scope.$apply();
                // your error expectations
            });
        });
    });
}());