一尘不染

单元测试angular-bootstrap $ modal

angularjs

我在尝试为Angular-Bootstrap编写茉莉花单元测试时遇到问题$modal。确切的错误是 `Expected spy open to have
been called with [ { templateUrl : ‘/n/views/consent.html’, controller :
‘W2ConsentModal as w2modal’, resolve : { employee : Function }, size : ‘lg’ }
] but actual calls were [ { templateUrl : ‘/n/views/consent.html’, controller
‘W2ConsentModal as w2modal’, resolve : { employee : Function }, size : ‘lg’
} ]`

期望和实际模式选项对象是相同的。到底是怎么回事?

控制者

(function () {
    'use strict';

    angular
        .module('app')
        .controller('W2History', W2History);

    W2History.$inject = ['$scope', '$modal', 'w2Service'];

    function W2History($scope, $modal, w2Service) {
        /* jshint validthis:true */
        var vm = this;
        vm.showModal = showModal;

        function showModal(employee) {
            var modalInstance = $modal.open({
                templateUrl: '/n/views/consent.html',
                controller: 'W2ConsentModal as w2modal',
                resolve: {
                    employee: function () {
                        return employee;
                    }
                },
                size: 'lg'
            });

            modalInstance.result.then(function (didConsent) {
                // code omitted
            });
        }


    }
})();

测试

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

        var fakeModal = {
            result: {
                then: function (confirmCallback, cancelCallback) {
                    //Store the callbacks for later when the user clicks on the OK or Cancel button of the dialog
                    this.confirmCallBack = confirmCallback;
                    this.cancelCallback = cancelCallback;
                }
            },
            close: function (item) {
                //The user clicked OK on the modal dialog, call the stored confirm callback with the selected item
                this.result.confirmCallBack(item);
            },
            dismiss: function (type) {
                //The user clicked cancel on the modal dialog, call the stored cancel callback
                this.result.cancelCallback(type);
            }
        };

        var modalOptions = {
            templateUrl: '/n/views/consent.html',
            controller: 'W2ConsentModal as w2modal',
            resolve: {
                employee: function () {
                    return employee;
                }
            },
            size: 'lg'
        };

        beforeEach(function () {
            module('app');

            inject(function (_$controller_, _$rootScope_, _$modal_) {
                scope = _$rootScope_.$new();                         
                modal = _$modal_;

                spyOn(modal, 'open').and.returnValue(fakeModal);

                controller = _$controller_('W2History', {
                    $scope: scope,
                    $modal: modal,
                    w2Service: w2Srvc
                });

            });

        });

        it('Should correctly show the W2 consent modal', function () {
            var employee = terminatedaccessMocks.getCurrentUserInfo();

            controller.showModal(employee);
            expect(modal.open).toHaveBeenCalledWith(modalOptions);
        });



    });

阅读 227

收藏
2020-07-04

共1个答案

一尘不染

试试这个:

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

        var fakeModal = {
            result: {
                then: function (confirmCallback, cancelCallback) {
                    //Store the callbacks for later when the user clicks on the OK or Cancel button of the dialog
                    this.confirmCallBack = confirmCallback;
                    this.cancelCallback = cancelCallback;
                }
            },
            close: function (item) {
                //The user clicked OK on the modal dialog, call the stored confirm callback with the selected item
                this.result.confirmCallBack(item);
            },
            dismiss: function (type) {
                //The user clicked cancel on the modal dialog, call the stored cancel callback
                this.result.cancelCallback(type);
            }
        };

        var modalOptions = {
            templateUrl: '/n/views/consent.html',
            controller: 'W2ConsentModal as w2modal',
            resolve: {
                employee: jasmine.any(Function)
            },
            size: 'lg'
        };

        var actualOptions;

        beforeEach(function () {
            module('plunker');

            inject(function (_$controller_, _$rootScope_, _$modal_) {
                scope = _$rootScope_.$new();                         
                modal = _$modal_;

                spyOn(modal, 'open').and.callFake(function(options){
                    actualOptions = options;

                    return fakeModal;
                });

                controller = _$controller_('W2History', {
                    $scope: scope,
                    $modal: modal
                });

            });

        });

        it('Should correctly show the W2 consent modal', function () {
            var employee = { name : "test"};

            controller.showModal(employee);
            expect(modal.open).toHaveBeenCalledWith(modalOptions);
            expect(actualOptions.resolve.employee()).toEqual(employee);
        });
    });

朋克

说明

我们不应该期望实际值resolve.employee与假值相同,resolve.employee因为它resolve.employee是一个返回雇员的函数(在这种情况下,该雇员是在关闭中被捕获的)。函数可能相同,但
在运行时 返回的对象可能不同。

测试失败的原因是javascript比较函数的方式。看看这个小提琴。无论如何,我对此并不在乎,因为我们不应该期望
函数实现 。在这种情况下,我们关心的是resolve.employee返回与传入的对象相同的对象:

expect(actualOptions.resolve.employee()).toEqual(employee);

因此,这里的解决方案是:我们期望除之外的所有东西resolve.employee

var modalOptions = {
                templateUrl: '/n/views/consent.html',
                controller: 'W2ConsentModal as w2modal',
                resolve: {
                    employee: jasmine.any(Function) //don't care about the function as we check it separately.
                },
                size: 'lg'
            };

   expect(modal.open).toHaveBeenCalledWith(modalOptions);

resolve.employee首先捕获它来单独检查:

var actualOptions;

 spyOn(modal, 'open').and.callFake(function(options){
      actualOptions = options; //capture the actual options               
      return fakeModal;
 });

expect(actualOptions.resolve.employee()).toEqual(employee); //Check the returned employee is actually the one we pass in.
2020-07-04