0

我对 Angular 有以下情况:

Controller

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

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

Template

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

我不得不说我通常很困惑为什么Angular没有更好的方法将表单添加到控制器而不是自动添加this.formor $scope.form,这取决于您使用控制器的方式,但我猜这是另一个问题。

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

$controller('Controller as ctrl')

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

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

但是因为ng-controller在模板中开始了一个新的范围,我不能直接访问控制器$scope.ctrl,而是我必须做类似的事情$scope.$$childHead.login

...我觉得它变得太复杂了。编辑:更不用说 $$ 表示“私有”属性。

4

2 回答 2

2

I've solved it myself, but I'm leaving it here unaccepted because I don't think the solution is very nice. If anyone knows a better way, please post.

The problem with compiling templates is that it's also not possible to insert mock services in the controller, at least I didn't figure it out. You get a controller instance on $scope, like $scope.ctrl, but that's it.

The second attempt was to locate just the form in the template, compile and add it to a controller that was instantiated separately. This worked, but not really, because the $scope for the form and controller were different and so any update to a field didn't reflect on the controller state.

The way it works in the end is to instantiate the controller with a $scope

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

and then to compile the partial template (just the form) with the same $scope

var formTpl = angular.element(template).find('form');
form = $compile(formTpl)($scope);

This way, the controller ends up in $scope.ctrl, but because the form is already named name="ctrl.form" it gets inserted into $scope.ctrl.form and it's visible inside a controller.

于 2015-06-18T06:47:22.473 回答
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();

同时可以通过使用 Angular 的$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();
    });
});
于 2017-03-13T22:14:41.760 回答