在 Jasmine 单元测试中模拟 AngularJS 模块依赖项

Posted

技术标签:

【中文标题】在 Jasmine 单元测试中模拟 AngularJS 模块依赖项【英文标题】:Mocking AngularJS module dependencies in Jasmine unit tests 【发布时间】:2013-07-07 10:38:36 【问题描述】:

我试图在一个模块中对控制器代码进行单元测试,该模块将其他模块作为依赖项,但无法弄清楚如何正确模拟它们。

我正在使用 Jasmine 框架并使用 Karma (Testacular) 运行我的测试。

模块代码

var app = angular.module('events', ['af.widgets', 'angular-table']);

app.controller('eventsCtrl', function([dependencies])
    $scope.events = [];
    ...
);

规格代码

describe('events module', function()
    var $scope,
        ctrl;

    beforeEach(function()
        angular.mock.module('af.widgets', []);
        angular.mock.module('angular-table', []);
        module('events', ['af.widgets', 'angular-table']);
    );

    beforeEach(inject(function($rootScope, $controller)
        $scope = $rootScope.new();
        ctrl = $controller('NameCtrl', 
            $scope: $scope,
        );
    ));

    it('should have an empty events array', function()
        expect($scope.events).toBe([]);
    )
);

我得到的错误是 Karma 是“没有模块 af.widgets”,所以显然我没有正确地模拟模块依赖项。有什么提示吗?

【问题讨论】:

$scope = $rootScope.new();应该是 $scope = $rootScope.$new();(也许是我们的版本) 【参考方案1】:

这是我想出来的:

我没有在我的 karma.conf.js 文件中加载任何“angular-table”模块,因此出现了错误。起初这是故意的,因为我想在没有实际表模块的情况下测试“事件”模块。

通过在我的测试文件夹中创建一个名为“mocks/angular-table.js”的新文件并添加以下代码,我能够轻松地模拟“angular-table”模块:

/mocks/angular-table.js

'use-strict';
angular.module('angular-table', []);

我将此文件添加到我的 karma.conf.js 文件中,以及我想要测试的真实“事件”模块:

karma.conf.js

...
files = [
    JASMINE,
    JASMINE_ADAPTER,
    'scripts/libs/angular.js',
    'scripts/libs/angular-mocks.js',
    'scripts/events.js', // this is the real module.
    'scripts/mocks/*.js', //loads all custom mocks.
    'scripts/specs/*.spec.js' // loads my spec file.
] 
...

最后,在我的规范文件中,我能够通过在 beforeEach 块中分别调用它们来添加这两个模块:

specs/events.spec.js

beforeEach(function()
    module('angular-table');
    module('events');
);

我从this post 得到了以这种方式构建文件的想法

【讨论】:

你不是通过调用 angular.module 来模拟 'angular-table' 模块吗?我想你想调用模块,因为 angular-mocks 将它附加到全局范围?不管怎样,谢谢你,因为这帮助我建立并运行了我的规范。 "通过在我的测试文件夹中创建一个名为“mocks/angular-table.js”的新文件并添加以下代码,我能够轻松地模拟“angular-table”模块:/mocks/角表.js“ @fscof 该链接给出 404。【参考方案2】:

如果你想模拟一个声明一个或多个服务的模块,我使用了这个代码:

beforeEach(function()
    module('moduleToMock');
    module(function ($provide) 
        $provide.value('yourService', serviceMock);
    );
);

如果您要模拟的服务也是您要进行单元测试的服务(在另一个 jasmine 描述中),这很有用。 fscof 提出的解决方案很好,但是您不能为angular-table 模块创建单元测试。

【讨论】:

这是正确的方法。因为您通常不想对所有测试都使用一个模拟。也在这里:***.com/a/18756347/1105860 如果我想将serviceMock 放在另一个文件中,而不声明全局变量呢? 我更喜欢这种方法用于我自己的模块,但是我不想为第 3 方模块编写任何单元测试。在那种情况下,我更喜欢@fscof 他的解决方案。两者都是正确的,具体取决于上下文:-) 如果我想从 serviceMock 对象的方法返回 promise 怎么办。我需要$q,对吗?如何获得内部模块功能。我无法得到那个..你能帮帮我吗?【参考方案3】:

我最近发布了 ngImprovedTesting,它应该让 AngularJS 中的模拟测试更容易。

在您的情况下,只需在 Jasmine 测试中使用以下内容:

beforeEach(ModuleBuilder.forModule('events').serviceWithMocks('eventsCtrl').build());

有关 ngImprovedTesting 的更多信息,请查看其介绍性博文:http://blog.jdriven.com/2014/07/ng-improved-testing-mock-testing-for-angularjs-made-easy/

【讨论】:

以上是关于在 Jasmine 单元测试中模拟 AngularJS 模块依赖项的主要内容,如果未能解决你的问题,请参考以下文章

模拟指令以测试组件 - Angular 8 与 jasmine 和 Karma

如何使用 Angular 4 Jasmine 单元测试用例覆盖 IF/ELSE 条件

在 Angular 中使用 Jasmine 使用 *ngIf 指令时,如何对元素是不是可见进行单元测试

Angular 7:如何在 Jasmine 单元测试中解决 Hammer.js 依赖项

如何使用 Jasmine 为私有方法编写 Angular / TypeScript 单元测试

如何在 Angular 7 中使用 Karma/Jasmine 为 App_Initializer 编写单元测试用例