Caricamento di un file JSON fittizio all'interno del test Karma + AngularJS


85

Ho un'app AngularJS configurata con test utilizzando Karma + Jasmine. Desidero testare una funzione che accetta un oggetto JSON di grandi dimensioni, lo converte in un formato più utilizzabile dal resto dell'app e restituisce l'oggetto convertito. Questo è tutto.

Per i miei test, mi piacerebbe che avessi file JSON separati (* .json) con solo contenuto JSON fittizio, nessuno script. Per il test, mi piacerebbe poter caricare il file JSON e pompare l'oggetto nella funzione che sto testando.

So di poter incorporare il JSON all'interno di una finta fabbrica come descritto qui: http://dailyjs.com/2013/05/16/angularjs-5/ ma voglio davvero che il JSON non sia contenuto nello script - solo JSON diretto File.

Ho provato alcune cose, ma in questo campo sono abbastanza noob. Per prima cosa, ho impostato il mio Karma per includere il mio file JSON solo per vedere cosa avrebbe fatto:

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

Ciò ha portato a:

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

Quindi l'ho cambiato per servire solo i file e non "includerli":

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

Ora che sono serviti solo, ho pensato di provare a caricare il file usando $ http dalle mie specifiche:

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

Quando ho eseguito la specifica che ho ricevuto:

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

Che a mio avviso significa che si aspetta una risposta derisa da $ httpBackend. Quindi ... a questo punto non sapevo come caricare il file utilizzando le utilità Angular, quindi ho pensato di provare jQuery per vedere se potevo almeno farlo funzionare:

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

Questo risulta in:

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

Ispeziono questa richiesta in Charles e ne sto facendo una richiesta

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

Mentre il resto dei file che ho configurato per essere "incluso" da Karma vengono richiesti a, ad esempio:

/base/src/app.js

Apparentemente Karma sta configurando una sorta di directory di base da cui servire i file. Quindi per i calci ho cambiato la mia richiesta di dati jquery in

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

E funziona! Ma ora mi sento sporco e ho bisogno di fare una doccia. Aiutami a sentirmi di nuovo pulito.

Risposte:


82

Sto usando una configurazione angolare con seme angolare. Ho finito per risolverlo con file di fixture .json e jasmine-jquery.js. Altri avevano accennato a questa risposta, ma mi ci è voluto un po 'per mettere tutti i pezzi nel posto giusto. Spero che questo aiuti qualcun'altro.

Ho i miei file json in una cartella /test/mocke la mia webapp è in /app.

my karma.conf.jsha queste voci (tra le altre):

basePath: '../',

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

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

quindi il mio file di prova ha:

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

});

Il vero trucco era jasmine.getJSONFixtures().fixturesPath='base/test/mock'; che inizialmente l' avevo impostato su solo, test/mockma aveva bisogno basedi lì. Senza la base, ho ricevuto errori come questo:

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
Ciao Cameron, ricevo un errore: TypeError: Object # <Object> has no method 'getJSONFixtures' ... has a change been made to jasmine or something?
Melbourne2991

7
non mi rendevo conto di aver richiesto jasmine-jquery ... l'ho installato e l'errore è scomparso
Melbourne2991

Questo approccio sembra piuttosto prolisso e complicato ... Non so se questi "dispositivi" forniscono ulteriori vantaggi, ma l'approccio seguente vince se tutto ciò che vuoi è leggere un file JSON di tanto in tanto.
Settembre

43

Servire JSON tramite l'apparecchiatura è il più semplice, ma a causa della nostra configurazione non potevamo farlo facilmente, quindi ho scritto una funzione di supporto alternativa:

Repository

Installare

$ bower install karma-read-json --save

  OR

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

  OR

$ yarn add karma-read-json --dev

Utilizzo

  1. Metti karma-read-json.js nei tuoi file Karma. Esempio:

    files = [
      ...
      'bower_components/karma-read-json/karma-read-json.js',
      ...
    ]
    
  2. Assicurati che il tuo JSON sia servito da Karma. Esempio:

    files = [
      ...
      {pattern: 'json/**/*.json', included: false},
      ...
    ]
    
  3. Usa la readJSONfunzione nei tuoi test. Esempio:

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

1
karma-read-json è un'ottima opzione se non sei in grado di utilizzare o installare bower, cosa che richiede jasmine-jquery. (Criteri di grandi aziende, nel mio caso.) Ho appena installato tramite npm ( npmjs.com/package/karma-read-json ) e ha funzionato alla grande.
Melissa Avery-Weir

2
Penso che questo sia l'approccio migliore in quanto non richiede una dipendenza dalla pergola ... solo karma / jasmine e karma-read-json. Sono stato anche in grado di farlo correndo npm install karma-read-jsoninvece dibower install karma-read-json
Eric Fuller

Ottima risposta per l'approccio karma - grazie per la chiara descrizione!
nomadoj

A) un po 'nuovo su questa piattaforma, B) non usa jquery cercando di costruire un modulo angolare. Questo ha funzionato bene per me. la mia configurazione è stata soffocata sui file karma.config.json -> [] .. Non ho aggiunto nulla in karma.config.json .. Inoltre: "const valid_respond = readJSON ('../ assets / organization.json'); "dove asset è l'ubicazione standard degli asset.
terary

10

Ho lottato per trovare una soluzione per caricare dati esterni nei miei casi di prova. Il link sopra: http://dailyjs.com/2013/05/16/angularjs-5/ per me.

Alcune note:

"defaultJSON" deve essere utilizzato come chiave nel file di dati fittizi, questo va bene, poiché puoi semplicemente fare riferimento a defaultJSON.

mockedDashboardJSON.js:

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

Quindi nel file di prova:

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
    ....
}

Ho un dubbio .. Ci sarà un modulo per file json? perché ho provato ad aggiungere più di un valore su valori singoli, ricevo un errore di provider sconosciuto per il secondo json
Pawan

6

sembra che la tua soluzione sia quella giusta ma ci sono 2 cose che non mi piacciono:

  • usa il gelsomino
  • richiede una nuova curva di apprendimento

mi sono imbattuto in questo problema e ho dovuto risolverlo rapidamente perché non avevo tempo per la scadenza, e ho fatto quanto segue

la mia risorsa json era enorme e non potevo copiarla e incollarla nel test, quindi ho dovuto tenerla in un file separato, ma ho deciso di mantenerla come javascript anziché come json, e poi ho semplicemente fatto:

var someUniqueName = ... the json ...

e ho incluso questo nel karma conf include ..

posso ancora deridere una risposta http di backend se necessario con esso.

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

Potrei anche scrivere un nuovo modulo angolare da includere qui e quindi cambiare la risorsa json in qualcosa di simile

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

e poi semplicemente iniettare SomeUniqueName nel test, che sembra più pulito.

forse anche avvolgerlo in un servizio

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

questa soluzione per me era più veloce, altrettanto pulita e non richiedeva alcuna nuova curva di apprendimento. quindi preferisco questo.


4

Stavo cercando la stessa cosa. Proverò questo approccio . Utilizza i file di configurazione per includere i file di dati fittizi, ma i file sono un po 'più di json, perché il json deve essere passato al valore angular.module (' MockDataModule ') e quindi i tuoi unit test possono anche caricare più moduli e quindi il valore impostato è disponibile per essere iniettato nella chiamata beforeEach inject.

Ho anche trovato un altro approccio che sembra promettente per le richieste xhr che non sono costose, è un ottimo post che descrive i test intermedi, che se ho capito bene consente al tuo controller / servizio di recuperare effettivamente i dati come in un test e2e, ma il tuo test intermedio è effettivo accesso all'ambito del controller (e2e non credo).




1

Ecco un'alternativa alla risposta di Cameron , senza la necessità di jasmine-jqueryalcuna configurazione Karma aggiuntiva, per testare ad esempio un servizio Angular utilizzando $resource:

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

E il test unitario corrispondente:

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

Cosa sono $ as in $ .when e $ .getJSON?
Matt

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.