Завантаження фіктивного файлу JSON в тесті Karma + AngularJS


85

У мене встановлена ​​програма AngularJS з тестами за допомогою Karma + Jasmine. У мене є функція, яку я хочу протестувати, яка бере великий об’єкт 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

Очевидно, Карма створює якусь базову директорію для обслуговування файлів. Тож для ударів я змінив свій запит даних jquery на

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

І це працює! Але зараз я відчуваю бруд і маю прийняти душ. Допоможіть мені знову почуватися чистим.

Відповіді:


82

Я використовую кутову установку з кутовим насінням. Врешті-решт я вирішив це за допомогою прямих файлів приладів .json та jasmine-jquery.js. Інші натякали на цю відповідь, але мені знадобився деякий час, щоб привести всі шматки в потрібне місце. Сподіваюся, це допомагає комусь іншому.

У мене є json-файли в папці, /test/mockа мій веб-додаток знаходиться /app.

my 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: Об'єкт № <Об'єкт> не має методу «getJSONFixtures» ... чи було внесено зміни до жасмину чи чогось іншого?
Мельбурн2991,

7
не зрозумів, що мені потрібен jasmine-jquery ... встановив його, і помилка зникла
Melbourne2991

Цей підхід звучить досить багатослівно і складно ... Я не знаю, чи дають ці "пристосування" додаткові переваги, але підхід нижче виграє, якщо все, що вам потрібно, - це час від часу читати файл JSON.
Септаграм

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
karma-read-json - чудовий варіант, якщо ви не можете використовувати або встановити bower, чого вимагає jasmine-jquery. (У моєму випадку політика Big-corp.) Я щойно встановив за допомогою npm ( npmjs.com/package/karma-read-json ), і він чудово працював.
Меліса Ейвері-Вір

2
Я вважаю, що це найкращий підхід, оскільки він не вимагає залежності від лука ... просто карма / жасмин і karma-read-json. Я навіть зміг це зробити, бігаючи npm install karma-read-jsonзамістьbower install karma-read-json
Ерік Фуллер

Чудовий відгук для підходу до карми - дякую за чіткий опис!
кочовий

A) щось нове для цієї платформи, B) не використовуючи jquery, намагаючись побудувати кутовий модуль. Це добре в мене вийшло. моє налаштування задихнулося на karma.config.json -> файли [] .. Я нічого не додав у karma.config.json .. Також: "const valid_respond = readJSON ('../ assets / organization.json'); "де активи - це стандартне розташування активів.
терарі

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

схоже, ваше рішення є правильним, але є 2 речі, які мені не подобаються:

  • в ньому використовується жасмин
  • це вимагає нової кривої навчання

я просто зіткнувся з цією проблемою і мав її швидко вирішити, оскільки у мене не залишилося часу до кінцевого терміну, і я зробив наступне

мій json ресурс був величезним, і я не міг скопіювати його, щоб вставити його в тест, тому мені довелося зберегти його окремим файлом - але я вирішив зберегти його як javascript, а не json, а потім просто зробив:

var someUniqueName = ... the json ...

і я включив це до карми, включає конф ..

я все ще можу знущатися над бекендом 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

Я шукав те саме. Я збираюся спробувати такий підхід . Він використовує конфігураційні файли для включення макетних файлів даних, але файли трохи більше, ніж json, тому що json потрібно передати angular.module ('MockDataModule'). Значення, а потім ваші модульні тести можуть також завантажувати кілька модулів а потім набір значень доступний для введення у виклик beforeEach inject.

Також знайшов ще один підхід, який виглядає багатообіцяючим для xhr-запитів, які не є дорогими, це чудова публікація, яка описує проміжне тестування, яке, якщо я правильно розумію, дозволяє вашому контролеру / службі насправді отримувати дані, як у тесті e2e, але ваш пробний тест фактично має доступ до області контролера (e2e, я не думаю).




1

Ось альтернатива відповіді Камерона , без необхідності jasmine-jqueryдодаткової конфігурації Karma, а також для тестування, наприклад, служби Angular за допомогою $resource:

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?
Метт

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.