我有一个Angular组件,MyComponent,它调用一个返回Observable的方法并订阅它,类似
export class MyComponent {
someProperty;
constructor(service: MyService) {}
someButtonClicked() {
this.service.doStuffAsync().subscribe(
resp => this.someProperty = resp;
);
}
}
@Injectable()
export MyService {
doStuffAsync() {
// returns an Observable which notifies asychronously, e.g. like HttoClient.get(url)
}
}
我想测试方法someButtonClicked()
,因此我创建了一个MyServiceMock类,并将其注入测试
export class MyServiceMock {
doStuffAsync() {
return of({// some object}).pipe(observeOn(asyncScheduler));
}
}
无论出于何种原因,我都希望MyServiceMock的doStuffAsync()
是异步的,因此使用observeOn(asyncScheduler)
。
但在这一点上,我不知道如何测试someButtonClicked()
。我尝试过不同的策略,例如以下
beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [
{ provide: MyService, useClass: MyServiceMock },
]
}).compileComponents();
}));
let fixture: ComponentFixture<MyComponent>;
let component: MyComponent;
beforeEach(() => {
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('test someButtonClicked', async(() => {
component.someButtonClicked();
fixture.whenStable().then(() => {
expect(component.someProperty).toBeDefined();
});
}));
但由于MyServiceMock的CCD_ 5是异步的。
因此,我的问题是,测试订阅异步Observable的方法引起的副作用(即someProperty
设置正确(的最佳策略是什么。
// All code should be synchronous within this it block
it('test someButtonClicked', async(() => {
// sync - button clicks are synchronous
component.someButtonClicked();
// but after btn clicks, we need to let some async code to finish
// like rxjs subscriptions etc.
await fixture.whenStable();
// and then continue
expect(component.someProperty).toBeDefined();
}));
不使用fixture.whenStable().then()
我使用一个名为发射的辅助函数
export const emitted = obs$ => new Promise(function(resolve, reject) {
const emitted$ = new Subject();
obs$.pipe(takeUntil(emitted$)).subscribe(
_ => {
emitted$.next();
emitted$.complete();
resolve(true);
},
_ => {
emitted$.next();
emitted$.complete();
reject('An error occurred');
}
)
});
如果您的模拟服务与组件共享相同的可观察实例
export class MyServiceMock {
private obs$ = of({// some object}).pipe(observeOn(asyncScheduler));
doStuffAsync() {
return obs$;
}
}
在你的规格内,你可以等待它发出
it('test someButtonClicked', async(async () => {
component.someButtonClicked();
const service = TestBed.get(MyService);
await emitted(service.doStuffAsync());
expect(component.someProperty).toBeDefined();
}));
看到您订阅了与组件相同的observable实例,您就知道组件已经运行了它的observator函数,就像您在组件之后订阅的一样。