我的服务是一个单例,在其构造函数中,它调用一个函数来进行API调用。初始化服务时,此方法非常有用,因为它降低了调用这些应用程序启动Api所需的复杂性和导入。不仅如此,它还使服务独立,因为它不需要依赖AppComponent
来导入和调用Api函数。
在应用程序负载上实例化Singleton服务:app.module.ts
....
export class AppModule {
constructor(private applicationSettings: ApplicationSettings) {
}
}
...
application-settings.ts
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ApplicationSettings{
...
constructor( private httpClient: HttpClient ){
this.LoadSettings();
}
private LoadSettings() {
this.httpClient.get<any>(this.settingsApiUrl, { observe: 'response' })
.pipe(
retry(3)
).subscribe(
data => this.ApiSuccess(data),
error => this.ApiError(error)
);
}
...
}
application-settings.spec.ts
import { ApplicationSettings } from './application-settings.service';
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { environment } from '@environments/environment';
let applicationSettings;
let httpMock: HttpTestingController;
let settingsApiUrl = environment.ApplicationSettings;
describe('ApplicationSettings', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
ApplicationSettings
],
imports: [
HttpClientTestingModule
]
});
});
beforeEach(() => {
applicationSettings = TestBed.get(ApplicationSettings);
httpMock = TestBed.get(HttpTestingController);
// Attempt to catch from constructor
httpMock.expectOne({
url: settingsApiUrl,
method: 'get'
}).flush({});
httpMock.verify();
});
describe('Tests To Pass', () => {
fit('should create the app', () => {
expect(applicationSettings).toBeDefined();
});
fit('should be successfull and call ApiSuccess', () => {
spyOn(applicationSettings, 'ApiSuccess');
httpMock.expectOne({
url: settingsApiUrl,
method: 'get'
}).flush({});
applicationSettings.LoadSettings();
expect(applicationSettings.ApiSuccess).toHaveBeenCalled();
});
...
});
});
在运行我的测试用例时,有时它们可以工作,但是80%的时间中它们将引发错误。一个测试可能抛出1,另一个可能抛出3,另一个可能抛出5(不一定按该顺序:
[object ErrorEvent] thrown
[object ErrorEvent] thrown
[object ErrorEvent] thrown
它会说:
Error: Expected one matching request for criteria "Match method: get, URL: //localhost/api/appSettings", found none.
如果我删除了主httpMock.expectOne
中的BeforeEach()
(我在那一行上有注释,表示试图抓住构造函数)。然后每个测试都会通过此错误:
Expected no open requests, found 1: GET //localhost/...
就我所知,它创建和使用AppSettings服务的新实例的每个测试都与构造函数中的Api调用有关,这是100%的肯定。
在将调用移到构造函数之前,所有测试都通过了。
答案 0 :(得分:0)
经过广泛的测试,我发现问题出在我正在处理从构造函数中调用LoadSettings()APi的方式中。正确的实现方式是:
beforeEach(() => {
applicationSettings = TestBed.get(ApplicationSettings);
httpMock = TestBed.get(HttpTestingController);
// Catches the call from the constructor
httpMock.expectOne({
url: settingsApiUrl,
method: 'get'
});
httpMock.verify();
});
在此之前,主要概念是正确的,但是我删除了.flush({})
,并且工作正常。从我对同花顺的阅读中可以得出以下定义,并且可以找到here:
为计时器中的计时器模拟异步时间流逝 通过清空宏任务队列直到其为空来创建fakeAsync区域。的 返回值是原本应经过的毫秒数 过去了。
我认为正在发生的事情是每次执行测试之前发生的事情发生之前,flush()
正在以某种方式将http
请求从队列中移出,从而导致致命的问题。在测试中。或使用冲洗功能可以防止api调用的发生。