2015-06-17 106 views
0

我有以下的情況與角:單元測試ControllerAs在AngularJS形式

Controller

function Controller() { 
    // form used in template 
    this.form ... 
} 

模板,有一個表格,並使用該控制器

Template

<div ng-controller="Controller as ctrl"> 
    <form name="ctrl.form"> 
    ... 
</div> 

我不得不說,我在一般困惑爲什麼A除了自動添加this.form$scope.form,取決於您如何使用控制器,ngular沒有更好的方式將表單添加到控制器,但這是我想要的另一個問題。

我現在真正的問題是,我不知道我應該如何測試這個。如果我只是實例化控制器的測試,然後我的形式是不確定的

$controller('Controller as ctrl')

我沒有找到一個方法,僅通過編譯模板

$scope = $rootScope.$new(); 
$compile(template)($scope); 

但由於ng-controller模板開始新的範圍,我不能直接訪問控制器與$scope.ctrl,而不是我需要做的事情,如$scope.$$childHead.login

...我覺得它變得太複雜licated。編輯:更不用說$$表示「私人」財產。

回答

2

我自己解決了這個問題,但我在這裏不接受,因爲我不認爲解決方案非常好。如果有人知道更好的方法,請發佈。

編譯模板的問題是,它也不可能在控制器中插入模擬服務,至少我沒弄明白。你在$ scope上得到一個控制器實例,如$scope.ctrl,但就是這樣。

第二次嘗試是在模板中找到表單,將其編譯並添加到單獨實例化的控制器中。這工作,但不是真的,因爲窗體和控制器的$範圍是不同的,所以任何更新字段沒有反映在控制器的狀態。

它的工作原理到底的方式是用$範圍來實例化控制器

ctrl = $controller('Controller as ctrl', { 
     someDependency: mockDependency, 
     $scope: $scope 
    }); 

,然後編譯使用相同的$範圍

var formTpl = angular.element(template).find('form'); 
form = $compile(formTpl)($scope); 
局部模板(表格)

這樣,控制器結束於$scope.ctrl,但由於表格已被命名爲name="ctrl.form",所以它被插入到$scope.ctrl.form中,並且它在控制器內部可見。

0

使用controllerAs,您可以訪問形式的測試,像這樣:

// 1. Create a new scope 
var $scope = $rootScope.$new(); 

// 2. Run the controller 
var Controller = $controller("Controller as ctrl", { $scope: $scope }); 

// 3. Compile the template against our scope 
// This will add property $scope.ctrl.form (assuming that form has name="ctrl.form") 
$compile(angular.element(templateHtml))($scope); 

// 4. Controller.form should now also be defined 
expect(Controller.form).toBeDefined(); 

同時嘲諷可以通過使用角度的$provide來實現:

beforeEach(angular.mock.module(function ($provide) { 
    function ApiServiceMock() { 
     this.getName() = function() { 
      return "Fake Name"; 
     }; 
    } 

    // Provide our mocked service instead of 'ApiService' 
    // when our controller's code requests to inject it 
    $provide.value("ApiService", ApiServiceMock); 
})); 

完整的示例(同時使用 - 嘲諷&與控制器形成彙編):

主應用程序代碼:

angular.module("my.module", []) 

    .service("ApiService", function() { 
     this.getName = function() { 
      return "Real Name"; 
     }; 
    }) 

    .controller("Controller", function (ApiService) { 
     var ctrl = this; 
     ctrl.someProperty = ApiService.getName(); 
    }); 

HTML:

<div ng-controller="Controller as ctrl"> 
    <form name="ctrl.form"> 
     <input type="email" name="email" /> 
    </form> 
</div> 

測試:

describe("Controller", function() { 
    var $scope, 
     Controller; 

    beforeEach(angular.mock.module("my.module")); 

    beforeEach(angular.mock.module(function ($provide) { 
     function ApiServiceMock() { 
      this.getName() = function() { 
       return "Fake Name"; 
      }; 
     } 

     $provide.value("ApiService", ApiServiceMock); 
    })); 

    beforeEach(inject(function ($rootScope, $controller, $compile) { 
     $scope = $rootScope.$new(); 

     Controller = $controller("Controller as ctrl", { $scope: $scope }); 

     // FIXME: Use your own method of retrieving template's HTML instead 'getTemplateContents' placeholder 
     var html = getTemplateContents("./my.template.html"), 
      formTpl = angular.element(html).find('form'); 

     $compile(formTpl)($scope); 
    })); 

    it('should contain someProperty', function() { 
     expect(Controller.someProperty).toBeDefined(); 
    }); 

    it('form should contain an email field', function() { 
     expect(Controller.form.email).toBeDefined(); 
    }); 
});