使用Jamine测试基于HTTP的异步功能:超时-在5000毫秒内未调用异步回调

问题描述 投票:0回答:1

内容:测试异步函数以返回依赖于嵌套http调用的Promise

WITH:Angular 9,茉莉花3.4.0

问题:错误:超时-在5,000毫秒(由jasmine.DEFAULT_TIMEOUT_INTERVAL设置)内未调用异步回调错误:未找到任何打开的请求,发现1:GET http://localhost:9876/24a27be6-9f62-4156-8fd4-adcd945ec909

我想在以下服务中测试loadUserData()。请注意,loadUserData()是私有的,this.someOtherService.getTokenViaHttp()进行了另一个http调用以获取标头的令牌(我不知道这是相关的,现在我开始对所有问题进行质疑)。

import ...

export interface UserData {...}

@Injectable()
export class UserDataManagementService {
  private userID: string | undefined;
  public userData: UserData;

  constructor(...) {}

  private async loadUserData() {
    const headers = await this.getHeaders();
    return this.httpClient
      .get<UserData>(window.location.origin + '/' + this.userID, { headers })
      .toPromise()
      .then((data) => {
         this.userData = data;
      })
      .catch((e) => {
        this.logger.error('Error in loadUserData: ', e);
      });
  }

  private async getHeaders() {
    let headers = new HttpHeaders({
      'key': 'value'
    });
    const token = await this.someOtherService.getTokenViaHttp();
    headers = headers.append('Authorization', `Bearer ${token.accessToken.encoded}`);
    return headers;
  }
}

这是我的测试:

import ...
const mockUserData: UserData = {...};

describe('UserDataManagementService', () => {
  let httpTestingController: HttpTestingController;
  let service: UserDataManagementService;
  let someOtherService: SomeOtherService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [
        UserDataManagementService,
        //I still need this service for other tests
        {
          provide: SomeOtherService,

          useClass: class {},
        },
      ],
    });
    httpTestingController = TestBed.get(HttpTestingController);
    service = TestBed.get(UserDataManagementService);
    someOtherService = TestBed.get(SomeOtherService);
  });

  afterEach(() => {
//If I move it to the test, the error "Expected no open requests, found 1" disappears, but I guess just because it somehow misses the request
    httpTestingController.verify();
  });


describe('loadUserData', () => {
    it('should return user data on success', (done) => {
      (service as any).userID = '24a27be6-9f62-4156-8fd4-adcd945ec909';

      //I am trying here to mock getHeaders() to avoid additional http calls

      const getHeadersSpy = spyOn(
        TestBed.get(UserDataManagementService),
        'getHeaders',
      ).and.callFake(() => {
        return Promise.resolve(new HttpHeaders({ key: 'value' }));
      });

      (service as any).loadUserData().then(() => {
        expect((service as any).userData).toEqual(mockUserData);
        expect(getHeadersSpy).toHaveBeenCalled();
        const req = httpTestingController.expectOne(
          'http://localhost:9876/24a27be6-9f62-4156-8fd4-adcd945ec909',
        );
        expect(req.request.method).toEqual('GET');
        req.flush(mockUserData);
        done();
      });
    });
  });
});

我尝试过的东西很远:

  • 试图将默认超时时间增加到20000ms-没有起作用
  • 完成/异步/等待等的不同组合
  • httpTestingController.expectOne在then()之外的位置(虽然没有任何意义,但是我已经尝试了所有方法)
  • 如果将httpTestingController.verify()放入此测试中,错误“预期没有打开的请求...”将消失]]
  • 这不是以下内容的重复:

  • 我的函数返回一个承诺,例如here
  • 我使用done(),例如here
  • 我没有像here这样的长期任务,>
  • fakeAsync也无济于事...
  • 内容:测试一个异步函数,该函数返回依赖于嵌套http调用的Promise,其中包括:Angular 9,Jasmine 3.4.0问题:错误:超时-在5000毫秒内未调用异步回调(由...设置)]] >> < [

    虽然我无法重现您的测试环境,但由于您的模拟请求从未得到满足,因此您的测试似乎正在超时。它从未实现的原因是因为您在旨在处理响应的回调中刷新了测试请求。

    (service as any).loadUserData().then(() => { const req = httpTestingController.expectOne( 'http://localhost:9876/24a27be6-9f62-4156-8fd4-adcd945ec909', ); expect((service as any).userData).toEqual(mockUserData); expect(getHeadersSpy).toHaveBeenCalled(); expect(req.request.method).toEqual('GET'); // this line tells the test scaffolding to fulfill the request req.flush(mockUserData); done(); });

    我希望如果您重构刷新请求,那么您的测试将不会超时(由于其他原因仍然可能失败)。>>

    const req = httpTestingController.expectOne('http://localhost:9876/24a27be6-9f62-4156-8fd4-adcd945ec909'); (service as any).loadUserData().then(() => { expect((service as any).userData).toEqual(mockUserData); expect(getHeadersSpy).toHaveBeenCalled(); expect(req.request.method).toEqual('GET'); done(); }); req.flush(mockUserData); // <= essentially: 'call my callback now!'

angular promise callback jasmine karma-jasmine
1个回答
0
投票
虽然我无法重现您的测试环境,但由于您的模拟请求从未得到满足,因此您的测试似乎正在超时。它从未实现的原因是因为您在旨在处理响应的回调中刷新了测试请求。

(service as any).loadUserData().then(() => { const req = httpTestingController.expectOne( 'http://localhost:9876/24a27be6-9f62-4156-8fd4-adcd945ec909', ); expect((service as any).userData).toEqual(mockUserData); expect(getHeadersSpy).toHaveBeenCalled(); expect(req.request.method).toEqual('GET'); // this line tells the test scaffolding to fulfill the request req.flush(mockUserData); done(); });

© www.soinside.com 2019 - 2024. All rights reserved.