我有一个具有耗时异步操作的服务:
@Injectable({
  providedIn: 'root'
})
export class TestService{
public timeConsumingMethod() {
      setTimeout(() => someTimeConsumingMethod()});
}
private someTimeConsumingMethod(){}
}我想编写一个测试(使用Jasmine),它将等待setTimeout方法中的代码完成处理(宏任务队列将为空):
describe('TestService', () => {
  let service: TestService;
  beforeEach(() => {
    TestBed.configureTestingModule({});
    service = TestBed.inject(TestService);
  });
  it('should be created', () => {
    service.timeConsumingMethod();
    //expect(result_of_timeConsumingMethod).toBe(some_result);
  });
});不幸的是,我无法让它发挥作用。
fakeAsync不适合,因为它只允许向前移动时间或空/丢弃任务队列,但它没有“等待”宏任务完成的工具。async/await也不适合,因为timeConsumingMethod是同步的(尽管它在setTimeout中触发异步任务)。waitForAsync,因为没有等待任务的工具(类似于fixture.whenStable()的工具是合适的,但是没有这样的工具用于角度服务,夹具只对组件起作用)。最后,我挣扎于:“1个计时器仍在队列中”的错误或错误,说明我的测试期望没有满足。
唯一可行的解决方案是使用茉莉花的done回调并等待固定的秒数:
  it('should be created', () => {
    service.timeConsumingMethod();
    setTimeout(()=>{
       //expect(result_of_timeConsumingMethod).toBe(some_result);
       done();
     }, 60000);
  });但这是一个糟糕的解决方案;在我的实际例子中,我不知道我应该等待多少秒。
编辑:
另一种方法是将服务方法更改为返回可观察的,这将通知耗时处理的结束:
@Injectable({
    providedIn: 'root'
})
export class TestService {
    public timeConsumingMethod(): Observable<boolean> {
        const isDone$ = new BehaviorSubject<boolean>(false);
        setTimeout(() => {
            try {
                this.someTimeConsumingMethod();
            }
            finally {
                isDone$.next(true);
                isDone$.complete();
            }
        });
        return isDone$.asObservable();
    }
    private someTimeConsumingMethod() { }
}然后在测试方法中使用async/await:
describe('TestService', () => {
  let service: TestService;
  beforeEach(() => {
    TestBed.configureTestingModule({});
    service = TestBed.inject(TestService);
  });
  it('should be created', async () => {
    await service.timeConsumingMethod().toPromise();
    //expect(result_of_timeConsumingMethod).toBe(some_result);
  });
});但我仍然不满意这一点,因为它驱动应用程序代码更改。代码更简单,并且做了以前应该做的事情。现在,仅仅因为需要编写测试代码,测试代码变得非常复杂。
发布于 2022-02-15 16:33:49
由于您不知道等待的时间,所以我认为您可以使用async/await和waitUntil的辅助实用程序函数。检查这关于如何实现waitUntil实用程序函数的答案。
it('should be created', async () => {
    service.timeConsumingMethod();
    // wait until what is returned from the lamda function returns true
    await waitUntil(() => result_of_timeConsumingMethod === some_result);
    // make your assertion
    expect(result_of_timeConsumingMethod).toBe(some_result);
  });发布于 2022-09-28 22:24:14
您可以使用flush(),它:
刷新所有挂起的微任务,并通过耗尽宏任务队列来模拟fakeAsync区域中计时器的异步传递时间,直到它为空(文档)。
describe('TestService', () => {
  let service: TestService;
  beforeEach(() => {
    TestBed.configureTestingModule({});
    service = TestBed.inject(TestService);
  });
  it('should be created', fakeAsync (() => {
    service.timeConsumingMethod();
    // this will make sure all asynchronous operations are completed
    // so the following expect statements can be executed safely on the result of this operation.
    flush();  
    expect(result_of_timeConsumingMethod).toBe(some_result);
  }));
});https://stackoverflow.com/questions/71129844
复制相似问题