2017-09-12 30 views
0

設置:加載配置數據的APP_INITIALIZER服務ConfigurationService正在整個應用程序組件和服務中使用。當單元測試組件時,它會讀取配置文件並正確評估。當使用配置的單元測試服務失敗時。Angular2/Jasmine:以另一個服務作爲依賴性的測試服務

它設置如下:

app.module.ts

export function ConfigurationFactory(config: ConfigurationService): any { 
    // this line actually triggers the loading of the config file 
    return() => config.load(); 
} 

@NgModule({ 
    bootrstrap: {}, 
    ..., 
    providers : [ 
    ConfigurationService, 
    { 
     deps: [ ConfigurationService ], 
     multi: true, 
     provide: APP_INITIALIZER, 
     useFactory: ConfigurationFactory, 
    } 
    ] 
}) 

ConfigurationService.ts

@Injectable() 
export class ConfigurationService { 

    // error holder 
    public error: boolean = false; 
    // data holder 
    public data: any = {}; 
    // config file url 
    private configUrl: string = './assets/config/config.json'; 

    constructor(private http: Http) { 
    } 
    /** 
    * reads config file 
    */ 
    public load(): Promise<any> { 
    return this.http.get(this.configUrl) 
     .map((response: any) => response.json()) 
     .toPromise() 
     .then((data: any) => this.data = data) 
     .catch((err: any) => Promise.resolve()); 
    } 

} 

這裏是TestableService.service.ts使用配置服務的也是

@Injectable() 
export class TestableService extends SomeAbstractHttpService { 
    constructor(http: Http, 
       private config: ConfigurationService) { 
    super(http); 
    } 

    public setRequest(sessionId: string, isIdent: boolean): void { 
    if (isIdent) { 
     this.resourceUrl = `${ this.config.data.contextRootRest}/documents/ident/${sessionId}`; 
    } else { 
     this.resourceUrl = `${ this.config.data.contextRootRest}/documents/noident/${sessionId}`; 
    } 
    this.headers = new Headers(); 
    this.headers.append('Content-Type', 'application/json'); 
    this.headers.append('Accept', 'application/json, application/pdf'); 
    this.requestOptions = new RequestOptions({ 
     headers: this.headers, 
     responseType: ResponseContentType.Blob 
    }); 
    } 
} 

我們spec文件,TestableService.service.spec.ts

export function ConfigurationFactory(config: ConfigurationService): any { 
    return() => config.load(); 
} 

describe('TestableService',() => { 

    // not ideal to hardcode it here, I would prefer using the same config file, which is used across the app! 
    let mockConfig: any = {contextRootRest: 'rest/'}; 
    let theService: TestableService; 

    beforeEach(async(() => { 
    TestBed.configureTestingModule({ 
     imports: [ 
     HttpModule, 
     ], 
     providers: [ 
     TestableService, 
     MockDataService, 
     { provide: XHRBackend, useClass: MockBackend }, 
     ConfigurationService, 
     { 
      // Provider for APP_INITIALIZER 
      deps: [ ConfigurationService ], 
      multi: true, 
      provide: APP_INITIALIZER, 
      useFactory: ConfigurationFactory, 
     }, 
     ] 
    }); 
    })); 

    // I suspect, that using APP_INITIALIZER at this stage is goofy, 
    // as I do not in fact instantiate the app, only the service. 
    // What would be the correct way to do it here? 

    beforeEach(inject([ TestableService, XHRBackend ], (service: TestableService, backend: MockBackend) => { 
    theService = service; 
    mockBackend = backend; 
    })); 

    it('should set request correctly', () => { 
    theService.setRequest('1234567890', true); 
    expect(theService.resourceUrl) 
     .toEqual(`${ mockConfig.contextRootRest }/documents/ident/1234567890`); 
    }); 
}); 

它失敗Expected 'undefined/documents/ident/1234567890' to equal 'rest/documents/ident/1234567890' - 這意味着,配置服務尚未在TestableService加載在所有。有任何想法嗎?

回答

0

上面的代碼實際上是不好的。幾個小時後,我們發現了這種方式,這是一個更清潔,更好的解決方案。

因此,由於配置文件位於我們的資產目錄中,因此我們可以將其直接導入到spec文件中。我們還使用了一個模擬的ConfigurationService提供者,就是這樣。這裏是spec.ts文件

import { ConfigurationService } from '../../common/config/configuration.service'; 
import * as config from '../../../assets/config/config.json'; 

const mockConfig: any = config; 

export class ConfigurationFactory { 
    // no methods as in the original ConfigurationService, just the object var 
    public data: any = mockConfig; 
} 

describe('TestableService',() => { 

    let theService: TestableService; 

    beforeEach(() => { 
    TestBed.configureTestingModule({ 
     providers: [ 
     TestableService, ... 
     { provide: ConfigurationService, useClass: ConfigurationFactory }, 
     ] 
    }); 
    }); 

    beforeEach(inject([ TestableService ], 
     (service: TestableService) => { 
     theService = service; 
    })); 

    it('should set request correctly', () => { 
    theService.setRequest('1234567890', true); 
    expect(theService.resourceUrl) 
     .toEqual(`${ mockConfig.contextRootRest }/documents/ident/1234567890`); 
    }); 
} 

的東西另一個例子的方式太複雜,其中一個更簡單的解決方案是在表面上得到解決...:/