Chargement d'un fichier JSON simulé dans le test Karma+AngularJS

J'ai une application AngularJS mise en place avec des tests utilisant Karma+Jasmine. J'ai une fonction que je veux tester qui prend un grand objet JSON, le convertit en un format qui est plus consommable par le reste de l'application, et renvoie cet objet converti. C'est tout.

pour mes tests, j'aimerais que vous ayez des fichiers JSON séparés (*.json) avec le contenu de JSON simulé seulement--pas de script. Pour le test, j'aimerais pouvoir charger le fichier JSON et pomper l'objet dans la fonction je suis test.

je sais que je peux intégrer le JSON dans un simulacre d'usine comme décrit ici: http://dailyjs.com/2013/05/16/angularjs-5/ mais je veux vraiment le JSON pour ne pas être contenue dans un script--tout droit des fichiers JSON.

j'ai essayé quelques trucs, mais je suis plutôt nul dans ce domaine. Tout d'abord, j'ai installé mon Karma pour inclure mon fichier JSON juste pour voir ce qu'il ferait:

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

ce qui a abouti à:

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

alors je l'ai changé pour juste servir les fichiers et pas" inclure "eux:

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

maintenant qu'ils sont seulement servis, j'ai pensé que je pourrais essayer de charger dans le fichier en utilisant $ http à partir de mon spec:

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

Quand j'ai couru les spécifications que j'ai reçu:

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

ce qui, à mon avis, signifie qu'il attend une réponse ridiculisée de $httpBackend. Donc ... à ce point je ne savais pas comment chargez le fichier en utilisant des utilitaires angulaires donc j'ai pensé que j'essaierais jQuery pour voir si je pouvais au moins obtenir que cela fonctionne:

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

il en résulte:

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

j'inspecte cette demande dans Charles et il fait une demande à

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

alors que le reste des fichiers que J'ai configurés pour être "inclus" par Karma sont demandés à, par exemple:

/base/src/app.js

apparemment Karma configurer une sorte de répertoire de base pour servir les fichiers à partir. J'ai donc changé ma demande de données jquery en

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

et ça marche! Mais maintenant je me sens sale et j'ai besoin de prendre une douche. Aidez-moi à me sentir propre.

83
demandé sur Aaronius 2013-06-28 21:28:09

8 réponses

j'utilise une configuration angulaire avec une graine angulaire. J'ai fini la résolution de ce droit .JSON fixture files et jasmine-jquery.js. D'autres ont fait allusion à cette réponse, mais il m'a fallu un certain temps pour obtenir toutes les pièces au bon endroit. J'espère que cela aide quelqu'un d'autre.

j'ai mes fichiers json dans un dossier /test/mock et mon webapp est dans /app .

mon karma.conf.js a ces entrées (entre autres):

basePath: '../',

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

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

alors mon fichier test a:

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

});

le vrai truc était le jasmine.getJSONFixtures().fixturesPath='base/test/mock'; À l'origine, je l'avais simplement réglé sur test/mock mais il avait besoin du base là-dedans. Sans la base, j'ai eu des erreurs comme celle-ci:

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
80
répondu Cameron 2013-08-30 01:44:39

servir JSON via le fixe est le plus facile mais à cause de notre configuration nous ne pouvions pas le faire aussi facilement donc j'ai écrit une fonction d'aide alternative:

dépôt

Installer

$ bower install karma-read-json --save

  OR

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

  OR

$ yarn add karma-read-json --dev

Utilisation

  1. Mettre karma-lire-json.js dans vos dossiers Karma. Exemple:

    files = [
      ...
      'bower_components/karma-read-json/karma-read-json.js',
      ...
    ]
    
  2. assurez-vous que votre JSON est servi par le Karma. Exemple:

    files = [
      ...
      {pattern: 'json/**/*.json', included: false},
      ...
    ]
    
  3. utilisez la fonction readJSON dans vos tests. Exemple:

    var valid_respond = readJSON('json/foobar.json');
    $httpBackend.whenGET(/.*/).respond(valid_respond);
    
40
répondu PizzaPanther 2016-12-15 23:29:25

j'ai eu du mal à trouver une solution pour charger des données externes dans mes bases de test. Le lien ci-dessus: http://dailyjs.com/2013/05/16/angularjs-5 / A travaillé pour moi.

quelques notes:

"defaultJSON" doit être utilisé comme clé dans votre fichier de données simulé, c'est très bien, comme vous pouvez simplement vous référer à defaultJSON.

mockedDashboardJSON.js:

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

puis dans votre fichier test:

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
    ....
}
10
répondu TOBlender 2013-08-16 15:34:24

on dirait que votre solution est la bonne mais il y a 2 choses que je n'aime pas:

  • il utilise jasmin
  • il faut une nouvelle courbe d'apprentissage

je viens de rencontrer ce problème et j'ai dû le résoudre rapidement car je n'avais plus le temps pour la date limite, et j'ai fait ce qui suit

ma ressource json était énorme, et je ne pouvais pas copier coller dans le test donc j'ai dû le garder fichier séparé - mais j'ai décidé de le garder comme javascript plutôt que json, et puis j'ai tout simplement fait:

var someUniqueName = ... the json ...

et je l'ai inclus dans Karma conf includes..

je peux encore me moquer d'une réponse http d'arrière-plan si nécessaire avec elle.

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

je pourrais aussi écrire un nouveau module angulaire pour être inclus ici et puis changer la ressource json pour être quelque chose comme

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

et puis injecter simplement SomeUniqueName dans le test, qui semble plus propre.

peut-être même l'envelopper dans un service

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

ces solutions étaient plus rapides pour moi, tout aussi propres, et ne nécessitaient pas de nouvelle courbe d'apprentissage. donc, je préfère celui-ci.

6
répondu guy mograbi 2014-10-02 21:39:09

je cherchais la même chose. Je vais essayer cette approche . Il utilise les fichiers de configuration pour inclure les fichiers de données simulées, mais les fichiers sont un peu plus que json, parce que le json doit être passé à angular.module ('MockDataModule').la valeur et ensuite vos tests unitaires peuvent également charger plusieurs modules et ensuite le jeu de valeur est disponible pour être injecté dans l'appel avant chaque injection.

également trouvé une autre approche qui semble prometteur pour les requêtes xhr qui ne sont pas coûteuses, c'est un excellent post qui décrit le test de mi-chemin, qui si je comprends bien permet à votre contrôleur/service de récupérer effectivement des données comme dans un test e2e, mais votre test de mi-chemin a un accès réel à la portée du contrôleur (e2e ne le fait pas je pense).

4
répondu user1683523 2013-07-11 19:56:16

il y a des préprocesseurs Karma qui fonctionnent aussi avec les fichiers JSON. Il y en a un ici:

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

et sans vergogne, celui-ci est un que j'ai développé qui a besoin de soutien js

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

2
répondu sma 2014-06-04 12:49:44

vous pouvez utiliser le karma-html2js-préprocesseur pour obtenir les fichiers JSON ajoutés au __html_ global.

voir cette réponse pour plus de détails: https://stackoverflow.com/a/22103160/439021

1
répondu kenglxn 2017-05-23 11:46:55

Voici une alternative à Cameron 'S réponse, sans la nécessité de jasmine-jquery ni aucune config Karma supplémentaire, pour tester p.ex. un service angulaire en utilisant $resource :

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

et l'essai unitaire correspondant:

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();
    });
});
1
répondu Lucas Cimon 2017-05-23 11:54:34