设置:APP_INITIALIZER服务ConfigurationService
,用于加载配置数据,用于跨应用程序组件和服务。单元测试组件时,它会读取配置文件并正确评估。当使用配置的单元测试服务失败时。
设置如下:
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'
- 这意味着Config服务根本没有加载到TestableService。有什么想法吗?
答案 0 :(得分: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` );
});
}
另一个以太复杂的方式解决的事情的例子,表面上更简单的解决方案......:/