Angularjs单元测试:我做得对吗?

时间:2013-09-20 09:34:55

标签: unit-testing angularjs

我开始为我的角应用程序编写单元测试。 然而,在我看来,我使用了很多样板代码来初始化和测试控制器。

在这个单元测试中,我想测试在执行函数时是否将范围中的模型发送到Api。

我需要20行代码。这使得编写仅执行一项操作的单元测试变得不方便。 您是否有任何关于将代码大小变为较小块的提示?

这是我目前的单元测试:

'use strict';

describe('controllers', function(){
    beforeEach(module('kronos'));

    describe('CustomerSignupCtrl', function() {
        it('should send customer to Api on submit', inject(function($controller) {
            var scope = {};
            var $location = {};
            var Api = {
                signupCustomer: function(customer) {
                    expect(customer).toEqual({attrs: "customerdata"});
                    return {
                        success: function() { return this; },
                        error: function() { return this; }
                    };
                }
            };
            var ctrl = $controller('CustomerSignupCtrl', {
                $scope: scope,
                $location: location,
                Api: Api});
            scope.customer = {attrs: "customerdata"};
            scope.signup();
        }));
    });
});

我特别不喜欢的是以下几点

  • 我需要初始化所有依赖项,如果我使用它们无关紧要
  • Api返回一个我只需要的承诺,因为控制器正在期待承诺
  • 我需要初始化控制器。

如何让这段代码更短更明确?

编辑:我刚注意到我可以忽略此单元测试的$location服务。大 Edit2 :我发现了angular-app,这是一个很好的做法示例应用。在那里你可以找到specs with jasmine,它们写得非常好。

2 个答案:

答案 0 :(得分:0)

在describe范围中使用另一个beforeEach方法来设置范围,$ location,controller等,然后根据需要在测试中更改它们。 Js是动态的,所以一切都应该没问题。

您还可以提取您设置到函数中的每个对象,以便在需要时可以在测试中重新初始化它们。

describe('controllers', function(){
beforeEach(module('kronos'));

describe('CustomerSignupCtrl', function() {
    var controller, scope, $location, Api;

    beforeEach(function(){
        scope = {};
        $location = {};
        Api = {
            signupCustomer: function(customer) {
                expect(customer).toEqual({attrs: "customerdata"});
                return {
                    success: function() { return this; },
                    error: function() { return this; }
                };
            }
        };

        controller = makeController();
    })

    function makeController(){
        inject(function($controller){
            controller = $controller('CustomerSignupCtrl', {
            $scope: scope,
            $location: location,
            Api: Api});
        });
    }

    it('should send customer to Api on submit', function() {
        scope.customer = {attrs: "customerdata"};
        scope.signup();
    });
});

});

答案 1 :(得分:0)

您无法缩短代码。初始化,模拟和断言等事情必须在某个地方完成。但是,您可以通过解耦初始化和测试代码来提高代码的可读性。像这样:

describe('CustomerSignupCtrl', function(){

  var controller, scope, location, api;

  beforeEach(module('kronos'));

  // initialization
  beforeEach(inject(function($controller, $rootScope, $location, Api){
    scope = $rootScope.$new();
    location = $location;
    api = Api;
    controller = $controller('CustomerSignupCtrl', {
      $scope: scope, $location: location, Api: api});
  }));

  // test
  it('should send customer to Api on submit', function() {
    scope.customer = {attrs: "customerdata"};
    spyOn(api,'signupCustomer').andCallFake(function(customer) {    
      return {
        success: function() { return this; },
        error: function() { return this; }
      };
    });
    scope.signup();
    expect(api.signupCustomer).toHaveBeenCalledWith(scope.customer);
  });

});