单元测试ControllerAs与AngularJS中的表单

时间:2015-06-17 06:43:29

标签: javascript angularjs forms unit-testing controlleras

我对Angular有以下情况:

println

Controller

具有表单并使用此控制器的模板

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

Template

我不得不说我一般都很困惑为什么Angular除了自动添加<div ng-controller="Controller as ctrl"> <form name="ctrl.form"> ... </div> this.form之外没有更好的方法将表单添加到控制器,取决于你如何使用控制器,但我认为这是另一个问题。

我现在面临的真正问题是,我不确定应该如何测试。如果我只是在测试中实例化控制器,那么我的表单是未定义的

$scope.form

我确实找到了一种方法,只需编译模板

$controller('Controller as ctrl')

但是因为模板中的$scope = $rootScope.$new(); $compile(template)($scope); 启动了一个新范围,我无法直接使用ng-controller访问控制器,而是我必须执行$scope.ctrl之类的操作}

......我觉得它变得太复杂了。编辑:更不用说$$表示私人&#39;属性。

2 个答案:

答案 0 :(得分:2)

我自己已经解决了这个问题,但我离开这里是不可接受的,因为我不认为解决方案非常好。如果有人知道更好的方法,请发帖。

编译模板的问题是它也不可能在控制器中插入模拟服务,至少我没弄明白。你在$ scope上获得了一个控制器实例,比如$scope.ctrl,但就是这样。

第二次尝试是在模板中找到表单,编译并将其添加到单独实例化的控制器中。这有效,但不是真的,因为表单和控制器的$ scope是不同的,所以对字段的任何更新都没有反映在控制器状态。

它最终的工作方式是使用$ scope

实例化控制器
ctrl = $controller('Controller as ctrl', {
        someDependency: mockDependency,
        $scope: $scope
    });

然后使用相同的$ scope

编译部分模板(只是表单)
var formTpl = angular.element(template).find('form');
form = $compile(formTpl)($scope);

这样,控制器最终会在$scope.ctrl中,但由于表单已经命名为name="ctrl.form",因此它会插入到$scope.ctrl.form中,并且在控制器中可见。

答案 1 :(得分: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);
}));

完整示例(同时使用 - 使用controllerAs进行模拟和表格编译):

主要应用代码:

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