在Karma + AngularJS测试中加载模拟JSON文件


85

我有一个使用Karma + Jasmine进行测试的AngularJS应用程序。我有一个要测试的函数,该函数需要一个大型JSON对象,然后将其转换为应用程序的其余部分更易使用的格式,然后返回该转换后的对象。而已。

对于我的测试,我希望您有单独的JSON文件(* .json),仅包含模拟JSON内容-没有脚本。对于测试,我希望能够加载JSON文件并将对象泵入要测试的功能中。

我知道我可以按如下所述将JSON嵌入到模拟工厂中:http : //dailyjs.com/2013/05/16/angularjs-5/,但是我真的希望JSON不包含在脚本中-只是纯JSON文件。

我已经尝试了一些方法,但是在这个领域我还算是新手。首先,我将Karma设置为包括JSON文件,以查看其作用:

files = [
    ...
    'mock-data/**/*.json'
    ...
]

结果是:

Chrome 27.0 (Mac) ERROR
Uncaught SyntaxError: Unexpected token :
at /Users/aaron/p4workspace4/depot/sitecatalyst/branches/anomaly_detection/client/anomaly-detection/mock-data/two-metrics-with-anomalies.json:2

因此,然后我将其更改为仅提供文件,而不是“包含”它们:

files = [
    ...
    { pattern: 'mock-data/**/*.json', included: false }
    ...
]

现在只提供服务了,我想我会尝试从规格中使用$ http加载文件:

$http('mock-data/two-metrics-with-anomalies.json')

运行规范时,我收到:

Error: Unexpected request: GET mock-data/two-metrics-with-anomalies.json

以我的理解,这意味着它期望来自$ httpBackend的模拟响应。所以...在这一点上,我不知道如何使用Angular实用程序加载文件,所以我想尝试一下jQuery,看看是否至少可以使它正常工作:

$.getJSON('mock-data/two-metrics-with-anomalies.json').done(function(data) {
    console.log(data);
}).fail(function(response) {
    console.log(response);
});

结果是:

Chrome 27.0 (Mac) LOG: { readyState: 4,
responseText: 'NOT FOUND',
status: 404,
statusText: 'Not Found' }

我在查尔斯(Charles)中检查了此请求,并且正在向

/mock-data/two-metrics-with-anomalies.json

而我请求配置为由Karma“包括”的其余文件,例如:

/base/src/app.js

显然,Karma建立了某种基础目录来提供文件。所以对于踢我改变了我的jQuery数据请求

$.getJSON('base/mock-data/two-metrics-with-anomalies.json')...

而且有效!但是现在我感到很脏,需要洗个澡。再次帮助我感到干净。

Answers:


82

我正在使用带有角度种子的角度设置。我最终通过直接的.json固定文件和jasmine-jquery.js解决了这个问题。其他人都提到了这个答案,但我花了一些时间才能将所有内容都放在正确的位置。我希望这可以帮助其他人。

我的文件夹中有json文件,/test/mock而Webapp在中/app

karma.conf.js有这些条目(以及其他条目):

basePath: '../',

files: [
      ... 
      'test/vendor/jasmine-jquery.js',
      'test/unit/**/*.js',

      // fixtures
      {pattern: 'test/mock/*.json', watched: true, served: true, included: false}
    ],

然后我的测试文件有:

describe('JobsCtrl', function(){
var $httpBackend, createController, scope;

beforeEach(inject(function ($injector, $rootScope, $controller) {

    $httpBackend = $injector.get('$httpBackend');
    jasmine.getJSONFixtures().fixturesPath='base/test/mock';

    $httpBackend.whenGET('http://blahblahurl/resultset/').respond(
        getJSONFixture('test_resultset_list.json')
    );

    scope = $rootScope.$new();
    $controller('JobsCtrl', {'$scope': scope});

}));


it('should have some resultsets', function() {
    $httpBackend.flush();
    expect(scope.result_sets.length).toBe(59);
});

});

真正的把戏是jasmine.getJSONFixtures().fixturesPath='base/test/mock'; 我最初将其设置为,test/mock但是它需要base在那里。没有基础,我会得到如下错误:

Error: JSONFixture could not be loaded: /test/mock/test_resultset_list.json (status: error, message: undefined)
at /Users/camd/gitspace/treeherder-ui/webapp/test/vendor/jasmine-jquery.js:295

1
嗨,卡梅隆,我收到一个错误:TypeError:对象#<Object>没有方法'getJSONFixtures'...对茉莉花进行了更改吗?
Melbourne2991

7
没意识到我需要茉莉花jquery ...安装它并且错误消失了
Melbourne2991

这种方法听起来很冗长和复杂……我不知道这些“固定装置”是否还能带来其他好处,但是如果您想要的只是不时读取JSON文件,则下面的方法胜出。
Septagram'3

43

通过固定装置提供JSON是最简单的方法,但是由于我们的设置,我们无法轻松做到这一点,因此我编写了一个替代的辅助函数:

资料库

安装

$ bower install karma-read-json --save

  OR

$ npm install karma-read-json --save-dev

  OR

$ yarn add karma-read-json --dev

用法

  1. 将karma-read-json.js放入您的Karma文件中。例:

    files = [
      ...
      'bower_components/karma-read-json/karma-read-json.js',
      ...
    ]
    
  2. 确保您的JSON由Karma提供。例:

    files = [
      ...
      {pattern: 'json/**/*.json', included: false},
      ...
    ]
    
  3. readJSON在测试中使用该功能。例:

    var valid_respond = readJSON('json/foobar.json');
    $httpBackend.whenGET(/.*/).respond(valid_respond);
    

1
如果您无法使用或安装jasmine-jquery所需的bower,则karma-read-json是一个不错的选择。(就我而言,是大公司政策。)我只是通过npm(npmjs.com/package/karma-read-json)安装了,效果很好。
Melissa Avery-Weir

2
我认为这是最好的方法,因为它不需要依赖于bower ...只需karma / jasmine和karma-read-json。我什至可以通过运行npm install karma-read-json而不是bower install karma-read-json
埃里克·富勒

对业力方法的好评-感谢您的清晰说明!
nomadoj '16

A)对该平台来说有点新,B)不使用jquery尝试构建Angular模块。这对我来说很好。我的设置在karma.config.json-> files []上出现了问题。 ”,其中资产是资产的标准位置。
terary

10

我一直在努力寻找一种将外部数据加载到我的测试用例中的解决方案。上面的链接:http : //dailyjs.com/2013/05/16/angularjs-5/为我工作。

一些注意事项:

需要将“ defaultJSON”用作模拟数据文件中的键,这很好,因为您可以引用defaultJSON。

mockedDashboardJSON.js:

'use strict'
angular.module('mockedDashboardJSON',[])
.value('defaultJSON',{
    fakeData1:{'really':'fake2'},
    fakeData2:{'history':'faked'}
});

然后在您的测试文件中:

beforeEach(module('yourApp','mockedDashboardJSON'));
var YourControlNameCtrl, scope, $httpBackend, mockedDashboardJSON;
beforeEach(function(_$httpBackend_,defaultJSON){
    $httpBackend.when('GET','yourAPI/call/here').respond(defaultJSON.fakeData1);
    //Your controller setup 
    ....
});

it('should test my fake stuff',function(){
    $httpBackend.flush();
    //your test expectation stuff here
    ....
}

我对此表示怀疑。每个json文件是否会有一个模块?因为我尝试在单个值上添加多个值,所以我收到第二个json的未知提供程序错误
Pawan

6

看起来您的解决方案是正确的解决方案,但是有两件事我不喜欢:

  • 它使用茉莉花
  • 它需要新的学习曲线

我刚遇到这个问题,不得不迅速解决,因为我没有时间来截止日期,所以我做了以下工作

我的json资源很大,我无法将其复制粘贴到测试中,因此我不得不将其保存为单独的文件-但我决定将其保留为javascript而不是json,然后我干脆做到了:

var someUniqueName = ... the json ...

我将其包含在业力配置文件中。

如果需要,我仍然可以模拟后端http响应。

$httpBackend.whenGET('/some/path').respond(someUniqueName);

我还可以编写一个新的angular模块,将其包含在此处,然后将json资源更改为类似

angular.module('hugeJsonResource', []).constant('SomeUniqueName', ... the json ... );

然后简单地注入SomeUniqueName看起来更干净的测试中。

甚至将其包装在服务中

angular.module('allTestResources',[]).service('AllTestResources', function AllTestResources( SomeUniqueName , SomeOtherUniqueName, ... ){
   this.resource1 = SomeUniqueName;
   this.resource2 = SomeOtherUniqueName; 
})

对我而言,此解决方案更快,更干净,并且不需要任何新的学习过程。所以我更喜欢这个。


4

我在找同样的东西。我将尝试这种方法。它使用配置文件包括模拟数据文件,但是文件比json多一点,因为需要将json传递给angular.module('MockDataModule')。value,然后您的单元测试也可以加载多个模块然后可以将值集注入到beforeEach注入调用中。

还发现了另一种方法,该方法对于不昂贵的xhr请求似乎很有希望,这是一篇描述中途测试的好文章,如果我理解正确,它可以使您的控制器/服务像在e2e测试中一样实际检索数据,但是中途测试具有实际意义访问控制器作用域(我不认为e2e)。




1

这是Cameron答案的替代方法,无需使用jasmine-jquery任何额外的Karma配置,即可使用$resource以下方法测试Angular服务:

angular.module('myApp').factory('MyService', function ($resource) {
    var Service = $resource('/:user/resultset');
    return {
        getResultSet: function (user) {
            return Service.get({user: user}).$promise;
        }
    };
});

以及相应的单元测试:

describe('MyServiceTest', function(){
    var $httpBackend, MyService, testResultSet, otherTestData ;

    beforeEach(function (done) {
        module('myApp');
        inject(function ($injector) {
            $httpBackend = $injector.get('$httpBackend');
            MyService = $injector.get('MyService');
        });
        // Loading fixtures
        $.when(
            $.getJSON('base/test/mock/test_resultset.json', function (data) { testResultSet = data; }),
            $.getJSON('base/test/mock/test_other_data.json', function (data) { otherTestData = data; })
        ).then(done);
    });

    it('should have some resultset', function() {
        $httpBackend.expectGET('/blahblahurl/resultset').respond(testResultSet);
        MyService.getResultSet('blahblahurl').then(function (resultSet) {
            expect(resultSet.length).toBe(59);
        });
        $httpBackend.flush();
    });
});

$ .when和$ .getJSON中的$是什么?
马特

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.