首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何用耗时的异步方法来测试角度服务?

如何用耗时的异步方法来测试角度服务?
EN

Stack Overflow用户
提问于 2022-02-15 16:17:59
回答 2查看 1K关注 0票数 1

我有一个具有耗时异步操作的服务:

代码语言:javascript
运行
复制
@Injectable({
  providedIn: 'root'
})
export class TestService{

public timeConsumingMethod() {
      setTimeout(() => someTimeConsumingMethod()});
}
private someTimeConsumingMethod(){}
}

我想编写一个测试(使用Jasmine),它将等待setTimeout方法中的代码完成处理(宏任务队列将为空):

代码语言:javascript
运行
复制
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回调并等待固定的秒数:

代码语言:javascript
运行
复制
  it('should be created', () => {
    service.timeConsumingMethod();
    setTimeout(()=>{
       //expect(result_of_timeConsumingMethod).toBe(some_result);
       done();
     }, 60000);
  });

但这是一个糟糕的解决方案;在我的实际例子中,我不知道我应该等待多少秒。

编辑:

另一种方法是将服务方法更改为返回可观察的,这将通知耗时处理的结束:

代码语言:javascript
运行
复制
@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

代码语言:javascript
运行
复制
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);
  });
});

但我仍然不满意这一点,因为它驱动应用程序代码更改。代码更简单,并且做了以前应该做的事情。现在,仅仅因为需要编写测试代码,测试代码变得非常复杂。

EN

回答 2

Stack Overflow用户

发布于 2022-02-15 16:33:49

由于您不知道等待的时间,所以我认为您可以使用async/awaitwaitUntil的辅助实用程序函数。检查关于如何实现waitUntil实用程序函数的答案。

代码语言:javascript
运行
复制
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);
  });
票数 0
EN

Stack Overflow用户

发布于 2022-09-28 22:24:14

您可以使用flush(),它:

刷新所有挂起的微任务,并通过耗尽宏任务队列来模拟fakeAsync区域中计时器的异步传递时间,直到它为空(文档)。

代码语言:javascript
运行
复制
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);
  }));
});
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71129844

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档