Angular 7 单元测试:Observable 订阅调用

4

我在我的Angular应用程序中有一个GeoLocationService,如下所示。

import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Observable";

@Injectable()
export class GeoLocationService {
  coordinates: any;

  constructor() {}

  public getPosition(): Observable<Position> {
    return Observable.create(observer => {
      navigator.geolocation.watchPosition((pos: Position) => {
        observer.next(pos);
      }),
        () => {
          console.log("Position is not available");
        },
        {
          enableHighAccuracy: true
        };
    });
  }
}

我想对这个服务进行单元测试,以确保getPosition()函数返回一个可用的Observable。以下是我的测试代码。

import { TestBed, fakeAsync } from "@angular/core/testing";

import { GeoLocationService } from "./geo-location.service";
import { take } from "rxjs/operators";

describe("GeoLocationService", () => {
  let service: GeoLocationService;
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [GeoLocationService]
    });
    service = TestBed.get(GeoLocationService);
  });


  it("should get observable value", fakeAsync((done: DoneFn) => {
    service
      .getPosition()
      .subscribe(value => {
        expect(value.coords).not.toBeUndefined();
        expect(value.coords).not.toBeNaN();
        expect(value.coords).not.toBeNull();
        done();
      });
  }));
});

这里发生的情况是,一旦我运行测试,测试成功了(这是因为测试中的subscribe块尚未运行)。在打开的Chrome浏览器窗口上(用于在karma中查看测试结果),我选择Allow,以使应用程序找到我的位置,在此时subscribe块就会运行,但由于此时it规范已经完成,因此我会收到一个console error

Uncaught Error: 'expect' was used when there was no current spec, this could be because an asynchronous test timed out。(“expect”被使用时没有当前规范,这可能是因为异步测试超时)。

我不知道执行这个测试的推荐方法是什么。

2个回答

5
我使用以下代码使其正常运行。
  it("should get current user coordinates", (done: DoneFn) => {
    let position: any;
    service.getPosition().subscribe(value => {
      position = value;
      expect(position.coords).not.toBeUndefined();
      expect(position.coords).not.toBeNaN();
      expect(position.coords).not.toBeNull();
      done();
    });
  });

为此,测试将等待您允许浏览器窗口获取您的位置。如果等待时间过长,它将抛出一个超时错误。这对我来说足够好,可以测试我想要的东西。


1
你可以使用tick(),它可以将测试虚拟成近似同步的形式 :-)
  it("should get observable value", fakeAsync((done: DoneFn) => {
    let matchValue = {coords: null};
    service
      .getPosition()
      .subscribe(value => {
        matchValue = value;
      });
      tick(2000); // whatever fits your needs
      expect(matchValue.coords).not.toBeUndefined();
      expect(matchValue.coords).not.toBeNaN();
      expect(matchValue.coords).not.toBeNull();
      done();
  }));

这样的话,我们也不需要 done 回调了。 - Ander2
“tick”没有等待,我不确定原因。由于这个原因,“matchValue.coords”仍然是“null”,导致测试失败,不确定为什么它没有等待。 - Mj1992
你选择了多长时间的滴答超时? - devnull69
我也试了5000,但不起作用。不过我设法解决了它,答案在下面发布了。 - Mj1992

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接