2017-06-02 7 views
0

Erste Entschuldigung für mein Englisch.Angular, Test, Dependency Injection, http.get ... Hilfe zu verstehen

Ich benutze Angular und entwickle einen einfachen Service mit seinem Test.

Der Dienst lädt eine JSON-Datei mit der http.get-Methode und speichert den Inhalt in einer Variablen. Das Ziel ist nicht wichtig.

Unter einem Code, der funktioniert:

Zuerst wird der Service

import {Http} from '@angular/http'; 
import {Injectable} from '@angular/core'; 
import {Constants} from 'config/constants'; 
import 'rxjs/Rx'; 
import 'rxjs/add/operator/catch'; 
import 'rxjs/add/operator/map'; 
import {Observable} from 'rxjs/Observable'; 

@Injectable() 
export class LoadJsonFileService { 
    private config: Object = null; 

    constructor(private http: Http) { 
    } 

    private loadJsonAndUpdateConfig() { 
    this.http 
     .get(Constants.CONFIG_FILE_NAME) 
     .map(response => response.json()) 
     .catch((error: any): any => { 
     return Observable.throw(error.json().error || 'Server error'); 
     }).subscribe((configJson) => { 
     this.config = configJson; 
     }); 
    } 
    public getConfig(key: string): string { 
    if (!this.config) { 
     this.loadJsonAndUpdateConfig(); 
    } 
    return this.config[key]; 
    } 
} 

Dann der Test:

import {BaseRequestOptions, ConnectionBackend, Http, RequestOptions, Response, ResponseOptions} from '@angular/http'; 
import {MockBackend, MockConnection} from '@angular/http/testing'; 
import {LoadJsonFileService} from './load-json-file.service'; 
import {inject, TestBed} from '@angular/core/testing'; 

describe('Test suite ...',() => { 
    beforeEach(() => { 
    TestBed.configureTestingModule({ 
     providers: [ 
     {provide: RequestOptions, useClass: BaseRequestOptions}, 
     {provide: ConnectionBackend, useClass: MockBackend}, 
     Http, 
     LoadJsonFileService 
     ] 
    }); 
    }); 

    it('The test ...', inject([ConnectionBackend, LoadJsonFileService], 
    (backend, 
    service: LoadJsonFileService) => { 
     backend.connections.subscribe((c: MockConnection) => { 
     c.mockRespond(new Response(new ResponseOptions({body: {key: 'foo'}}))); 
     }); 

     expect(service.getConfig('key')).toBe('foo'); 
    })); 

}); 

-Test ist OK.

Der Code, die nicht funktionieren, und ich weiß nicht, warum:

import {Http} from '@angular/http'; 
import {Injectable} from '@angular/core'; 
import {Constants} from 'config/constants'; 
import 'rxjs/Rx'; 
import 'rxjs/add/operator/catch'; 
import 'rxjs/add/operator/map'; 
import {Observable} from 'rxjs/Observable'; 

@Injectable() 
export class LoadJsonFileService { 
    private config: Object = null; 

    constructor(private http: Http) { 
    this.loadJsonAndUpdateConfig(); 
    } 

    private loadJsonAndUpdateConfig() { 
    this.http 
     .get(Constants.CONFIG_FILE_NAME) 
     .map(response => response.json()) 
     .catch((error: any): any => { 
     return Observable.throw(error.json().error || 'Server error'); 
     }).subscribe((configJson) => { 
     this.config = configJson; 
     }); 
    } 
    public getConfig(key: string): string { 
    return this.config[key]; 
    } 
} 

Der Unterschied den Aufruf von this.loadJsonAndUpdateConfig() im Konstruktor und nicht in der getConfig Methode. Test nicht bestanden:

TypeError: null is not an object (evaluating 'this.config[key]') 

Als ich setzen einige der Methode subscribe debuggen nie dergleichen auslösen, wenn http.get wird rufen nie ...

Ich bin verwirrt ist mir jemand dieses Verhalten erklären kann?

Danke,

Stef

Antwort

0

Lange Rede kurzer Sinn, nur Standardwert Variable

private config: Object = {}; 

Lange Version zuweisen: erste Codebeispiel auch nicht funktionieren sollte, es sei denn, Sie etwas zu config zuweisen Variable irgendwo oder Backend-Anfrage endet vor this.config[key] Stück wird ausgeführt (Race-Bedingung), aber wenn das lokal (oder in Tests) funktioniert, kann es auf dem Server brechen.

Grundsätzlich getConfig() heißt (ich nehme in Vorlage) vor this.config = configJson;. Http-Anfragen sind "asynchron", d. H. Js/ts/angular warten nicht, bis es abgeschlossen ist, der nachfolgende Code wird ausgeführt, unmittelbar nachdem die HTTP-Anfrage initiiert wurde.

Wenn Sie möchten, um es zu testen, Asynchron-Timeout vor der Rückkehr Wert, oder besser sehen Winkel Dokumentation auf InMemoryWebApiModule

+0

Dank aber die Frage war nicht, warum die Null-Fehler (dies ist eine Folge), mein Code hinzufügen, nur zu Stellen Sie sich die Frage vor: Warum wird die Methode 'http.get' nicht aufgerufen, wenn die Methode' loadJsonAndUpdateConfig() 'im Konstruktor aufgerufen wird, aber aufgerufen wird, wenn ich sie in die Methode' getConfig' setze? – Wilda