【问题标题】:In angular how can I test a scope function is being called in my directive?在角度如何测试我的指令中正在调用的范围函数?
【发布时间】:2016-07-20 11:26:42
【问题描述】:

如何在 Angular 中测试指令中调用的作用域函数?

我在 Angular 版本 1 中使用 jasmine、karma runner 和 js 单元测试。

这是我的指令代码:

angular.module("myApp.directives")
    .directive("test", ["$rootScope", function($rootScope) {
        return {
            restrict: "E",
            scope: {
                "figures": "="
            },
            templateUrl: "templates/components/test.html",
            link: function(scope) {

                scope.init = function() {
                    if (scope.figures !== undefined) {
                        for (let i = 0; i < scope.figures.length; i++) {
                            scope.figures[i].isModalVisible = false;
                        }
                    }
                };

                scope.init ();
            }
        };
    }]);

这是我的单元测试:

describe("test", function () {    
    var element,
        scope,
        otherScope
        mockData = [
            {                
                isModalVisible: true
            },
            {                
                isModalVisible: false
            }
        ];

    beforeEach(angular.mock.module("myApp.directives"));

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

        element = "<test figures=\"agg\"></test>";
        element = $compile(element)(scope);

        angular.element(document.body).append(element);

        scope.$digest();

        otherScope = element.isolateScope();

        spyOn(otherScope, "init");
    }));    

    //This one doesn't work
    it("should close all modals by default", function () {
         expect(otherScope.init).toHaveBeenCalled();
    });
});

这是我目前得到的错误:“ Expected spy init to have been called。”

【问题讨论】:

    标签: javascript angularjs unit-testing testing jasmine


    【解决方案1】:

    首先:您的spyOn(scope, "init")expect(scope, "init") 都在错误 范围内执行。您将 init inside 指令添加到隔离范围,因此它应该是 spyOn(otherScope, "init")expect(otherScope, "init")

    第二,第一点还是会失败。 :) 原因是 init() 只会在调用 link() 时执行一次,这将发生在你的 beforeEach 块内的 scope.$digest() 上——但你不在那里提供数据。您稍后在测试中提供它时为时已晚,因为指令已在第一个摘要循环中链接,并且 init() 不会在您的测试中的第二个 scope.$digect() 上调用。要解决这个问题,您需要将第一个摘要周期推迟到您在测试用例中准备好所有数据之后。

    第三,您需要先将 html 元素附加到 DOM,然后才编译它。在这样一个简单的情况下,它可能会起作用,但是如果您的元素内部的任何内容都需要父元素上的某处的指令(即内部的指令具有类似require: "^something" 的配置),那么编译将失败:只是没有包含新元素所需实体的父元素元素,直到您将其实际插入 DOM。

    更新

    你不能这样测试这个场景。安装 spy 的正确时间点是在将 init() 添加到作用域之后但在调用它之前,但问题是这个时间点位于 指令内,因为函数调用在添加后立即触发作用于范围。由于这一点不在 test 的代码中,因此您没有机会以这种方式编写 test。

    但是让我们从另一个角度考虑这种情况。 init() 是做什么的?它会重置数据阵列上的标志。因此,您可以使用truebefore $digest() 初始化这些标志,并且您可以检查这些标志是否在在调用$digest() 之后 被重置。通过这种方式,您可以轻松地准备数据并断言结果。您的测试将能够清楚地告诉您是否实际调用了 init(),甚至更多 - 如果它做了它应该做的事情。

    【讨论】:

    • 我设法根据您的指示使第一部分工作,例如这个期望:expect(otherScope.figures[0].isModalVisible).toEqual(false);但我无法让我的 spyOn 工作。我已经更新了上面的代码
    • 我昨晚做了那个,它奏效了。我只是想再检查一下指令第一次触发时是否调用了我的函数 init
    • @AngularM,这就是重点——你并不真正关心调用这个函数的唯一事实。它可能被调用但由于某种原因失败,或者您可以在将来更改实现并且某些标志将阻止此重置周期运行。所以只是调用函数的事实不会告诉你任何有价值的东西。你关心的是它的工作是否完成。
    猜你喜欢
    • 2018-08-05
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多