2017-09-12 43 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`); 
    }); 
} 

的东西另一个例子的方式太复杂,其中一个更简单的解决方案是在表面上得到解决...:/