【问题标题】:Unit testing $modal with Jasmine使用 Jasmine 对 $modal 进行单元测试
【发布时间】:2014-10-27 18:24:14
【问题描述】:

我有一个带有控制器的 Angular 应用程序,它在函数调用期间显示 Angular-Strap 模态窗口。它在 Chrome 中正常运行,但我无法让有效的单元测试正常工作。

App 模块和 FooController:

var app = angular.module("app", ["mgcrea.ngStrap"]);

app.controller("FooController", function($scope, $modal) {
    var fooModal = $modal({
        title: 'Foo',
        content:'Bar',
        show: false,
        html: true,
        backdrop: 'static',
        placement: 'center'});
    
    angular.extend($scope, {
        makeItFoo: function() {
            fooModal.show();
        }
    });
});

控制器规格:

describe('FooController', function () {
    var scope, controller, modal;

    beforeEach(module('app', function ($provide) {
        // Stub out $modal service
        $provide.value('$modal', function () {
            return {
                hide: function () { },
                show: function () { }
            };
        });
    }));

    beforeEach(inject(function ($rootScope, $controller, $injector) {
        //set up a new scope and the controller for the test
        scope = $rootScope.$new();
        controller = $controller('FooController', {$scope: scope});
        modal = $injector.get('$modal');
    }));

    it('should show the modal', function () {
        var modalSpy = spyOn(modal(), 'show');
        
        scope.makeItFoo();
        
        expect(modalSpy).toHaveBeenCalled();
    });
});

Here's a fiddle as well.

我希望我对 makeItFoo() 的调用会显示模态,但 Jasmine 未通过测试并出现错误 Expected spy show to have been called。我还尝试将模态的show 属性设置为true 而不是单独调用show(),并且我尝试了其他变体将$modal 服务存根并将其直接注入控制器,但它结束了出现同样的错误。

我正在使用 AngularJS 1.2.14、Angular-Strap 2.0.0 和 Jasmine 1.3.1。

【问题讨论】:

    标签: javascript angularjs angularjs-scope jasmine angular-strap


    【解决方案1】:

    而不是做这些。使用 show 和 hide 方法为 $modal 创建一个模拟对象,并设置您对它们的期望。

    describe('FooController', function () {
        var scope, controller, modal;
    
        beforeEach(module('app'));
    
        beforeEach(inject(function ($rootScope, $controller) {
            //set up a new scope and the controller for the test
            scope = $rootScope.$new();
            //Create spy object
            modal = jasmine.createSpyObj('modal', ['show', 'hide']);
            //provide modal as dependency to the controller.
            controller = $controller('FooController', {$scope: scope, $modal:modal});
    
        }));
    
        it('should show the modal', function () {
    
            scope.makeItFoo();
    
            expect(modal.show).toHaveBeenCalled();
        });
    });
    

    【讨论】:

    • 当你发布它时,我正处于我的回答中,你成功了;)
    • @maurycy 哈哈它有时也会发生在我身上.. :)
    • @PSL - 我不确定如何解释 JSFiddle 中 Jasmine 输出中的行号。我正在尝试将这个(非常)简化的示例复制回我的 IDE 中,以便我可以更好地理解它。一旦它在那里工作,我会再次回复。同时,here's an updated fiddle 显示最新错误。
    • @TheDIMMReaper 给你。我没有使用过这个 ng-strap,它似乎提供了一个构造函数而不是实例。以下是如何为此 plnkr.co/edit/C10qMz?p=preview 和您的茉莉花版本 jsfiddle.net/wovbzgr1 编写测试
    • @PSL - 你一针见血 - 很好地考虑为构造函数创建一个间谍并为其返回第二个间谍对象。这正是最初让我失望的原因。谢谢!
    【解决方案2】:

    模态显示是异步的。我在http://jsfiddle.net/jwom7ns2/1/ 更新了你的小提琴。

    更改以下部分:

    it('should show the modal', function (done) {
        var modalSpy = spyOn(modal(), 'show');
    
        scope.makeItFoo();
    
        setTimeout(function() {
            expect(modalSpy).toHaveBeenCalled();
            done();
        });
    
    });
    

    当模态显示发生时,超时包装器等待摘要发生。

    【讨论】:

    • 在您修改为什么scope.$apply? 的答案之前,我正要发表评论。但我认为这也可能是一个矫枉过正的恕我直言,因为 OP 已经创建了一个模拟 obj 然后设置了间谍。相反,一切都可以通过使用 jasmine 创建一个模拟对象来一次完成。另外你真的不需要$injector.get('$modal'),而是可以直接注入$modal
    • 谢谢,这绝对是一个可行的解决方案。我将首先介绍@PSL 模拟$modal 的方法,因为我不想明确地处理时间问题。如果我在那里遇到麻烦,我会记住你的解决方案。谢谢!
    猜你喜欢
    • 2014-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-28
    • 2017-02-28
    • 2018-06-02
    相关资源
    最近更新 更多