2015-07-01 14 views
20

sto cercando di testare un servizio che utilizza $http

var APIClient = function($http) { 
    this.send = function(data) { 
     $http({ 
      method: data.method, 
      url: data.url, 
      headers: data.headers, 
      data: data.data 
     }).success(function(response, status) { 
      data.success(response, status); 
     }).error(function(response, status) { 
      data.error(response, status); 
     }); 
    } 
} 

angular.module('api.client', []).factory('APIClient', ['$http' 
    function($http) { 
     var client = new APIClient($http); 

     return { 
      send: function(data) { 
       return client.send(data); 
      }, 
     } 

    } 
]); 

E il test

describe('send', function() { 

     var apiClient, $httpBackend; 

     beforeEach(module('compare')); 

     beforeEach(inject(function($injector) { 
      $httpBackend = $injector.get('$httpBackend'); 
      apiClient = $injector.get('APIClient'); 
     })); 

     it('Should check if send() exists', function() { 
      expect(apiClient.send).toBeDefined(); 
     }); 

     it('Should send GET request', function(done) { 
      var url = '/'; 

      $httpBackend.expect('GET', url).respond({}); 

      apiClient.send({ 
       url: url, 
       success: function(data, status) { 
        console.log(status); 
        done(); 
       }, 
       error: function(data, status) { 
        console.log(status); 
        done(); 
       } 
      }); 

      $httpBackend.flush(); 
     }); 
    }); 

Ma ho sempre questo errore

PhantomJS 1.9.8 (Mac OS X) send Should send GET request FAILED 
     Error: Unexpected request: GET templates/test.html 
     Expected GET/

l'URL previsto è sempre l'ultimo stato nel mio app.js In questo caso

// Ionic Starter App 

// angular.module is a global place for creating, registering and retrieving Angular modules 
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html) 
// the 2nd parameter is an array of 'requires' 
// 'starter.services' is found in services.js 
// 'starter.controllers' is found in controllers.js 

angular.module('compare', 
    [ 
     'ionic', 
     'manager.user', 
     'api.client', 
     'api.user', 
     'api.compare', 
     'user.controllers', 
     'test.controllers' 
    ] 
) 

    .run(function ($ionicPlatform) { 
     $ionicPlatform.ready(function() { 
      // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard 
      // for form inputs) 
      if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) { 
       cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); 
      } 
      if (window.StatusBar) { 
       // org.apache.cordova.statusbar required 
       StatusBar.styleLightContent(); 
      } 
     }); 
    }) 

    .config(function ($stateProvider, $urlRouterProvider) { 

     // Ionic uses AngularUI Router which uses the concept of states 
     // Learn more here: https://github.com/angular-ui/ui-router 
     // Set up the various states which the app can be in. 
     // Each state's controller can be found in controllers.js 
     $stateProvider 

      // setup an abstract state for the tabs directive 
      .state('tab', { 
       url: "/tab", 
       abstract: true, 
       templateUrl: "templates/tabs.html" 
      }) 

      // Each tab has its own nav history stack: 

      .state('tab.dash', { 
       url: '/dash', 
       views: { 
        'tab-dash': { 
         templateUrl: 'templates/tab-dash.html', 
         controller: 'DashCtrl' 
        } 
       } 
      }) 

      .state('subscription', { 
       url: '/subscription', 
       templateUrl: 'templates/subscription.html', 
       controller: 'SubscriptionCtrl' 
      }) 

      .state('login', { 
       url: '/login', 
       templateUrl: 'templates/login.html', 
       controller: 'LoginCtrl' 
      }) 

      .state('test-compare', { 
       url: '/test/compare', 
       templateUrl: 'templates/test.html', 
       controller: 'TestCompareCtrl' 
      }) 

     // if none of the above states are matched, use this as the fallback 
     $urlRouterProvider.otherwise('/login'); 

    }); 

non capisco il motivo per cui l'url sta cambiando sto dando / e prova templates/test.html che è sempre l'ultimo modello di Stato

+0

Quando si inietta '$ httpBackend' nei nostri test intercetta tutte le richieste http. Quindi ovviamente hai un codice (non da APIClient se questo è l'unico codice che viene presentato in OP) che attiva gli stati. Puoi fornire il codice che definisce il modulo 'compare'? –

+0

@ KirillSlatin Ho appena aggiornato l'ultimo codice per l'intero app.js – Ajouve

+0

Perché dichiarate il servizio 'APIClient' nel modulo' api.client', ma chiamate 'compare' nella suite di test per il servizio? –

risposta

6

questa è la seguente riga:

beforeEach(module('compare')); 

Qui si sta caricando l'intera app anziché solo l'apiClient. Essenzialmente, stai facendo un test di integrazione completo, invece di un test unitario.

Si dovrebbe caricare solo api.client.

beforeEach(module('api.client')); 

Qualcosa di utile da notare, si potrebbe anche fare qualcosa di simile:

$httpBackend.whenGET(/templates\/(.*)/).respond(''); che ignora praticamente tutti i modelli che vengono caricati da router, controller o direttive. Se lo fai, comunque, non sarà considerato un test unitario, perché non stai testando rigorosamente solo il tuo APIClient.

Un'altra nota utili:

Tutto ciò che si esegue all'interno di .run o .config non dovrebbe essere una funzione annonymous, in questo modo si potrebbe deridere esso.

Un esempio di questo sarebbe fare:

.config(CompareStateLoader); 

CompareStateLoader.$inject = [ 
    '$stateProvider', 
    '$urlRouterProvider' 
]; 

function CompareStateLoader(
    $stateProvider, 
    $urlRouterProvider 
){ 
    //configure states here 
} 

Facendo questo permetterebbe di deridere CompareStateLoader e caricare questo nella vostra test runner.

Per ulteriori informazioni, consultare la Guida allo stile angolare di John Papa here.

0
var apiClient, $httpBackend, $loc; 

    beforeEach(module('compare')); 

    beforeEach(inject(function($injector, $location) { 
     $httpBackend = $injector.get('$httpBackend'); 
     apiClient = $injector.get('APIClient'); 
     $loc = $location; 
    })); 


it ('Should send GET request', function(done) { 
     expect($loc.path()).toEqual(''); 
     var url = '/'; 

     $httpBackend.expect('GET', $loc.path('/')).respond({}); 

     apiClient.send({ 
      url: url, 
      success: function(data, status) { 
       console.log(status); 
       done(); 
      }, 
      error: function(data, status) { 
       console.log(status); 
       done(); 
      } 
     }); 

     $httpBackend.flush(); 
    }); 

Modifica Si dovrebbe usare angular-mock per utilizzare $ posizione

beforeEach(inject(function(_$httpBackend_, APIClient) { 
     $httpBackend = _$httpBackend_; 
     apiClient = APIClient; 
    })); 
+0

Provalo con 'expect ($ loc.path()). ToEqual ('');' e dammi il feedback – gr3g

+0

'expect ($ loc.path()). ToEqual ('');' funziona ma '$ loc.path ('/')' restituisce un oggetto e ho l'errore 'Expected GET [object Object]' e '$ loc.path ('/'). url()' restituisce '/' – Ajouve

+0

I Non sto usando il router UI, potrebbe essere il motivo per cui c'è un errore – gr3g

1

vorrei suggerire di compilare tutti i modelli in file JS (per esempio con grugnito "html2js" compito o karma preprocessore "ng-html2js") e non hanno il mal di testa con i modelli geting.

Oppure si potrebbe anche usare passthrough

$httpBackend.when('GET', /\.html$/).passThrough() 

Esempio - http://plnkr.co/edit/pbjcDl?p=preview

ma vorrei suggerire di usare prima opzione.

0

Aggiungi questa riga prima di ogni blocco - $ httpBackend.expect ('GET', "templates/test.html"). Rispondi (200);

Problemi correlati