【问题标题】:How to write mock in karma-jasmine for AngularJS unit testing如何在 karma-jasmine 中为 AngularJS 单元测试编写模拟
【发布时间】:2016-12-20 12:32:51
【问题描述】:

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

这是我的服务:

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

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

【问题讨论】:

  • 你不是在更新的问题中对不同的方法进行单元测试吗?
  • 对不起@tanmay。我已经更新了我的 spec.js 测试文件。
  • 你为什么在你的规范中调用scope.$apply()?如果删除它会发生什么?
  • 因为我在我的虚假服务中使用异步调用。所以我认为它需要 $apply() 或 $digest()。我说得对吗@tanmay?
  • 您可能需要在$scope.findData 通话之后执行此操作?另外,我添加了处理它的答案。

标签: angularjs unit-testing jasmine karma-jasmine


【解决方案1】:

您可能没有手动调用GET dashboard/views/dashboard-new.html,但$scope.$apply() 可能会以某种方式触发它,您只能处理它。

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

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

【讨论】:

    【解决方案2】:

    在 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
                });
            });
        });
    }());
    

    【讨论】:

    • 您的编码标准看起来很酷。但它会为一些以某种方式触发的意外请求提供错误。错误:意外请求:GET localhost:3000/api/employees 预期没有更多请求
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多