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

时间:2013-06-28 17:28:10

标签: angularjs karma-runner

我使用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' }

我在查尔斯检查这个请求,它正在向

发出请求
/mock-data/two-metrics-with-anomalies.json

而我所配置为由Karma“包含”的其余文件正在被请求,例如:

/base/src/app.js

显然,Karma正在设置某种基本目录来提供文件。所以对于踢,我将我的jquery数据请求更改为

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

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

7 个答案:

答案 0 :(得分:80)

我正在使用带角度种子的角度设置。我最终用直接的.json fixture文件和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 :(得分:42)

通过夹具提供JSON是最简单的,但由于我们的设置,我们不能轻易做到这一点,所以我写了另一个辅助函数:

Repository

安装

$ 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);
    

答案 2 :(得分: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
    ....
}

答案 3 :(得分:6)

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

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

我刚遇到这个问题并且必须快速解决它,因为我没有时间离开截止日期,我做了以下

我的json资源非常庞大,我无法将其粘贴到测试中,因此我必须将其保留为单独的文件 - 但我决定将其保留为javascript而不是json,然后我只是做了:

var someUniqueName = ... the json ...

并且我把它包括在karma conf包括..

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

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

我还可以编写一个新的角度模块,然后将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 :(得分:4)

我一直在找同样的事情。我要试试this approach。它使用配置文件来包含模拟数据文件,但文件比json多一点,因为需要将json传递给angular.module('MockDataModule')。value然后你的单元测试也可以加载多个模块然后可以将值集注入到beforeEach注入调用中。

同样发现another approach对于xhr请求看起来很有前途,这些请求并不昂贵,这是一个很好的帖子,描述了中途测试,如果我理解正确,让你的控制器/服务实际上检索数据,如在e2e测试,但是你的中途测试可以实际访问控制器范围(我认为e2e不是这样)。

答案 5 :(得分:2)

还有可以使用JSON文件的Karma预处理器。这里有一个:

https://www.npmjs.org/package/karma-ng-json2js-preprocessor

无耻的插件,这是我开发的具有RequireJS支持的插件

https://www.npmjs.org/package/karma-ng-json2js-preprocessor-requirejs

答案 6 :(得分:1)

您可以使用karma-html2js-preprocessor将json文件添加到__html__全局。

请参阅此答案以获取详细信息:https://stackoverflow.com/a/22103160/439021