Загрузка фиктивного файла JSON в тесте Karma + AngularJS


85

У меня есть приложение AngularJS, настроенное с помощью тестов с использованием Karma + Jasmine. У меня есть функция, которую я хочу протестировать, которая принимает большой объект JSON, преобразует его в формат, более удобный для остальной части приложения, и возвращает этот преобразованный объект. Вот и все.

Для моих тестов я бы хотел, чтобы у вас были отдельные файлы JSON (* .json) только с имитацией содержимого JSON - без скрипта. Для теста я хотел бы иметь возможность загрузить файл JSON и закачать объект в функцию, которую я тестирую.

Я знаю, что могу встроить JSON в макет фабрики, как описано здесь: http://dailyjs.com/2013/05/16/angularjs-5/, но я действительно хочу, чтобы JSON не содержался в скрипте - просто прямо JSON файлы.

Я пробовал кое-что, но в этой области я довольно новичок. Сначала я настроил свою карму, чтобы включить мой файл 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.

У меня 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 # <Object> не имеет метода getJSONFixtures ... были ли внесены изменения в жасмин или что-то в этом роде?
Melbourne2991

7
не понял, что мне нужен jasmine-jquery ... установил его, и ошибка исчезла
Melbourne2991

Этот подход звучит довольно многословно и сложно ... Я не знаю, предоставляют ли эти «приспособления» дополнительные преимущества, но подход, описанный ниже, выигрывает, если все, что вам нужно, - это время от времени читать файл JSON.
Септаграмма 01

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. (В моем случае политика большой корпорации). Я только что установил через npm ( npmjs.com/package/karma-read-json ), и он отлично сработал.
Мелисса Эйвери-Вейр,

2
Я думаю, что это лучший подход, поскольку он не требует зависимости от bower ... просто karma / jasmine и karma-read-json. Я даже смог сделать это, бегая npm install karma-read-jsonвместоbower install karma-read-json
Эрик Фуллер

Отличный отзыв за кармический подход - спасибо за четкое описание!
nomadoj 08

A) что-то новое для этой платформы, B) без использования jquery для создания модуля Angular. У меня это сработало. моя установка зависла от karma.config.json -> files [] .. Я ничего не добавил в karma.config.json .. Также: "const valid_respond = readJSON ('../ assets / organization.json'); «где активы - стандартное расположение активов.
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
Паван

6

похоже, что ваше решение правильное, но есть 2 вещи, которые мне в нем не нравятся:

  • он использует жасмин
  • это требует нового обучения

Я просто столкнулся с этой проблемой и должен был решить ее быстро, так как у меня не было времени до крайнего срока, и я сделал следующее

мой ресурс json был огромен, и я не мог скопировать и вставить его в тест, поэтому мне пришлось сохранить его в отдельном файле, но я решил оставить его как javascript, а не json, и тогда я просто сделал:

var someUniqueName = ... the json ...

и я включил это в karma conf.

Я все еще могу издеваться над 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 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();
    });
});

Что такое $ as в $ .when и $ .getJSON?
Мэтт

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.