【问题标题】:Angular with Jasmine: mocking factory servicesAngular 与 Jasmine:模拟工厂服务
【发布时间】:2015-05-02 05:09:07
【问题描述】:

我在 Angular JS 中定义了以下控制器,它使用来自 Angular Material 的服务:

angular.module('leopDirective', [])
    .controller('MenuCtrl', function ($scope, $timeout, $mdSidenav, $log)
{

    $scope.mdSidenav = $mdSidenav;

    $scope.close = function () {
        $mdSidenav('left').close().then(function () {
            $log.debug("close LEFT is done");
            $scope.closed = true;
        });
    };

});

这取决于我试图用我自己的工厂对象模拟的服务 $mdSidenav:

describe('Controller: MenuCtrl', function() {
    var $rootScope, $scope, $controller, $q, menuCtrl,
        mock__mdSidenav = function(component) {
            return {
                isMock: true,
                component: component,
                close: function () {}
            }
        };

    beforeEach(function () {
        module('leopDirective', function($provide) {
            $provide.value('$mdSidenav', mock__mdSidenav);
        });
        inject(function ($injector) {
            $rootScope = $injector.get('$rootScope');
            $controller = $injector.get('$controller');
            $q = $injector.get('$q');
            $scope = $rootScope.$new();
        });
        menuCtrl = $controller("MenuCtrl", { $scope: $scope });
    });

    it('should create the $mdSidenav object', function () {
        expect($scope.mdSidenav).toBeDefined();
    });

    describe('managing $mdSidenav', function () {
        it('should close the menu', function () {
            var data, deferred = $q.defer(), promise = deferred.promise;
            mock__mdSidenav.close = function() {
            return promise.then(function (response) {
                data = response.success;
            });
            $rootScope.$digest();
            $scope.close();
        };
    });
});

我的代码在下面plnkr

显然,它唯一不起作用的是我在测试的第二个“描述”块中将 $promise 分配给 close() 。执行此测试返回以下错误:

TypeError: Cannot read property 'then' of undefined
TypeError: Cannot read property 'then' of undefined
    at Scope.$scope.close (app.js:7:35)

是什么让我认为工厂本身或 promise 函数没有正确模拟。

  1. 这是模拟工厂的正确方法吗?
  2. 这是创建返回承诺的方法的正确方法吗?

【问题讨论】:

    标签: javascript angularjs unit-testing jasmine factory


    【解决方案1】:

    我不完全确定您要测试什么,但这就是您收到此错误消息的原因:

    您正在触发 $scope.close(),它没有被模拟。它是来自 MenuCtrl 的原始 $scope.close 方法。 close 方法依次触发 $mdSidenav('left').close().then... 并且在测试的参数中 $mdSidenav('left').close() 返回 undefined 这意味着它没有 then 方法.

    如果你想控制发生的事情,你应该为 $scope.close 或 $mdSidenav('left').close 创建一个间谍/模拟(这意味着模拟 $mdSidenav 函数以返回一个带有间谍的对象/模拟)。

    【讨论】:

    • 这正是我想要做的:我试图从 Angular Material 模拟“$mdSidenav”服务。正如您在 Jasmine 代码中看到的那样,我创建了一个名为“mock__mdSidenav”的模拟对象,我将其定义为一个函数,因为该服务是由工厂提供的。我调用 $provide.value 以替换原始服务,然后为“close()”方法创建“假”承诺返回(您可以看到我在第二个描述中的测试中重新定义了该方法)。
    【解决方案2】:

    这个问题的解决方法可以在以下帖子中找到:How to mock a service that returns a promise

    使代码工作的关键是在定义模拟对象期间使用 $q 而不关心其分辨率。显然,只有在必须使用模拟对象时,JavaScript 才会解析它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-22
      • 1970-01-01
      • 1970-01-01
      • 2015-07-07
      相关资源
      最近更新 更多