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


71

我正在尝试在将其他模块作为依赖项的模块中进行单元测试控制器代码的单元化,但是还无法弄清楚如何正确模拟它们。

我正在使用Jasmine Framework,并使用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是“ no module af.widgets”,因此显然我没有对模块依赖项进行模拟。有什么提示吗?


1
$ scope = $ rootScope.new(); 应该是$ scope = $ rootScope。$ new();(也许对于我们的版本而言)
Steve Black

Answers:


65

如果要模拟声明一个或多个服务的模块,请使用以下代码:

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

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


4
这是正确的方法。因为您通常不想在所有测试中使用一种模拟。Se也
位于

如果我要放入serviceMock另一个文件而不声明全局变量怎么办?
Cyril CHAPON 2015年

1
对于我自己的模块,我更喜欢这种方法,但是我不想为第三方模块编写任何单元测试。在那种情况下,我更喜欢@fscof他的解决方案。两者都是正确的,具体取决于上下文:-)
Pim Hazebroek '16

如果我想从serviceMock对象的方法返回promise怎么办。我需要$ q,对吧?如何获得模块内部功能。我无法理解。.你能帮我吗?
杰伊·舒克拉

46

这是我发现的:

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

通过在测试文件夹中创建一个名为“ 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');
});

我从这篇文章中想到了以这种方式构造文件的想法


2
您不是通过调用angular.module来嘲笑“ angular-table”模块吗?我认为您想调用模块,因为角度模拟会将其附加到全局范围?无论哪种方式,谢谢您,因为这可以帮助我启动和运行规格。
phillyslick 2014年

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

@fscof链接是给404
卢西奥

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/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.