函数中Restangular的jasmine测试用例

时间:2014-11-20 09:58:06

标签: javascript angularjs unit-testing jasmine restangular

如何为如下所示的场景编写Rectangular的jasmine测试

脚本

$scope.allEmployees = [{
            visible: true,
            empId: "EMP148"
 }];

$scope.employeeDocuments = {  "EMP148": [{
                                        "empId": "EMP148",
                                        "department": "Sales",
                                        "firstName": "Manu",
                                        "lastName": "Mathew",
                                        "place": "Kolkata"
                                        }]
                           };

var employeesCopy = angular.copy($scope.allEmployees);
$scope.allEmployees.push({visible: true, empId: "EMP489"});  

$scope.addEmployees = function (employeesCopy) {
    var newEmployee = {visible: true, empId: "EMP489"};
    var emplyeeList = {
        employees: $scope.allEmployees,
        newEmployee: newEmployee
    };
    Restangular.all('emp/getEmployees').post(emplyeeList).then(function (employees) {
        if (!_.isEmpty(employees[emplyeeList.newEmployee.empId])) {
            if ($scope.employeeDocuments.hasOwnProperty(emplyeeList.newEmployee.empId)) {
                delete $scope.employeeDocuments[emplyeeList.newEmployee.empId];
            }
            $scope.employeeDocuments[emplyeeList.newEmployee.empId] = employees[emplyeeList.newEmployee.empId];
            setMyEmployees(true);
            $scope.flag = true;
            console.log("success");
        } else {
            $scope.employeeDocuments = employeesCopy;
            console.log("no documents");
        }
        $scope.flag = false;
    }, function (error) {
        console.log("failed");
        $scope.flag = false;
    });
};

$scope.addEmployees(employeesCopy);
setMyEmployees = function (flag)
{
    // other implementation
};

我已经编写了一个如下所示的测试用例,但是我遇到了像spyOn could not find an object to spy upon for all()

这样的异常

测试用例

WORKING DEMO - 包含完整的逻辑以及测试用例

describe('Testing Controllers', function() {
    describe('Testing EmployeeController Controller', function() {
        var EmployeeController, $scope, $httpBackend, Restangular;

        beforeEach(function() {
           module('emp');
        }); 

        beforeEach(inject(function($controller, $rootScope, $filter, $injector, Restangular, $httpBackend) {
            $scope = $rootScope.$new();
            $httpBackend = $httpBackend;
            Restangular = $injector.get("Restangular");
            EmployeeController = $controller('EmployeeController ', {
                $rootScope: $rootScope,
                $scope: $scope,
                $filter: $filter
            });
        }));

        it('should add new employees when addEmployees() is called', inject(function($httpBackend)
        {
           $scope.allEmployees = [{
                                    visible: true,
                                    empId: "EMP148"
                              }];

           $scope.employeeDocuments = {  "EMP148": [{
                                            "empId": "EMP148",
                                            "department": "Sales",
                                            "firstName": "Manu",
                                            "lastName": "Mathew",
                                            "place": "Kolkata"
                                            }]
                                   };

           var employeesCopy = angular.copy($scope.allEmployees);

           spyOn(Restangular, 'all').andCallThrough();

           var newEmployee = {visible: true, empId: "EMP489"};
           var emplyeeList = {
                employees: $scope.allEmployees,
                newEmployee: newEmployee
           };

           var mockToReturn = {
                "EMP489": [{
                "empId": "EMP489",
                "department": "Sales",
                "firstName": "Ram",
                "lastName": "Mohan",
                "place": "Delhi"
                }]
            };
            $scope.addEmployees(employeesCopy);
            $httpBackend.expectPOST('emp/getEmployees',emplyeeList).respond(mockToReturn);
            expect(Restangular.all).toHaveBeenCalledWith('emp/getEmployees');
            expect(setMyEmployees(true)).toHaveBeenCalled();

        }));
    });
});

1 个答案:

答案 0 :(得分:6)

你有多重问题:

首先,要回答你的问题,请使用toHavebeenCalled,你必须先创建一个间谍。

我要做的是将setMyEmployees放在范围级别,然后在范围上添加间谍

spyOn($scope);

但是你有一个测试会产生异步请求,所以你的测试用例会失败,因为它会在异步请求成功之前到达终点。

使用jasmine 2,您可以使用done()进行异步测试:

it('should add new employees when addEmployees() is called', function(done) 
{
    //call when asyncronous operation is finish
    done();
}

但是按照你创建函数的方式,你不能使用done。 您必须在方法或承诺中有一个回调块

回调:

$scope.addEmployees = function(employeesCopy, success, failure)
{
    //code
    Restangular.all('user/getEmployees').post(emplyeeList).then(function(employees)
    {
        if (!_.isEmpty(employees[emplyeeList.employeeId]))
        {
           // code
        }
        else
        {
            // code
        }
        success();
        $scope.flag = false;
    }, function(error)
    {
        failure();
        $scope.flag = false;
    });
};

请注意toHaveBeenCall语法

it('should add new employees when addEmployees() is called', function(done) 
{
var employeesCopy = {
    firstName: "Manu",
    lastName: "Sam"
};

spyOn($scope);

$scope.addEmployees(employeesCopy, function(){

    done();

});

expect($scope.setMyEmployees).toHaveBeenCalledWith(true);
});

我更喜欢使用promise语法:

$scope.addEmployees = function(employeesCopy, defer)
{
    //code
    Restangular.all('user/getEmployees').post(emplyeeList).then(function(employees)
    {
        if (!_.isEmpty(employees[emplyeeList.employeeId]))
        {
           // code
        }
        else
        {
            // code
        }
        defer.resolve();
        $scope.flag = false;
    }, function(error)
    {
        defer.reject();
        $scope.flag = false;
    });
};


it('should add new employees when addEmployees() is called', function(done) 
{
var employeesCopy = {
    firstName: "Manu",
    lastName: "Sam"
};

spyOn($scope);

var defer = $q.defer;
defer.promise.then(function(){

    console.log("success");
    done();
}, function (){
    done();
    console.log("error");
});

$scope.addEmployees(employeesCopy, defer);

expect($scope.setMyEmployees).toHaveBeenCalledWith(true);
});

如果您希望测试真正统一,那么您将遇到的最后一个问题是模拟网络调用(否则您还会测试后端答案,这可能是您想要的) 如果你想模拟电话,你应该看看$ httpBackend,这篇博文似乎有更多的信息:https://ath3nd.wordpress.com/2013/08/05/15/(不是我的)

编辑,在测试之前添加依赖性,在它之前(),使用beforeEach:

var myService, Restangular;
    beforeEach(function() {
        inject(function($injector) {
            myService = $injector.get('MyService');//exemple service
            Restangular = $injector.get("Restangular");
        });
    });

编辑2:

好的,我没有正确解释,试试:

beforeEach(inject(function($controller, $rootScope, $filter, $injector, _Restangular_, _$httpBackend_) {
        $scope = $rootScope.$new();
        $httpBackend = _$httpBackend_;
        Restangular = _Restangular_;
        EmployeeController = $controller('EmployeeController ', {
            $rootScope: $rootScope,
            $scope: $scope,
            $filter: $filter
        });
    }));