Angular 7单元测试可观察的订阅呼叫

时间:2019-07-02 09:42:24

标签: angular unit-testing karma-jasmine

我在这样的角度应用程序中有一个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 browser window(用于查看业力测试结果)上,我为应用程序选择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

我不知道执行此测试的推荐方法是什么。如果有人可以帮助我,我将非常感激。

2 个答案:

答案 0 :(得分:1)

您可以使用 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(); })); 将测试伪装成同步的:-)

 {emails.map((email, i) => (
    <Grid item xs={12} sm={6}>
      <TextField
        className={classes.field}
        id="contactEmails"
        name="contactEmails"
        label="Contact Email(s)"
        fullWidth
        // onChange={change.bind(null, 'contactEmails')}
        autoComplete="lname"
        inputProps={{
          maxLength: 250
        }}
        value={emails[i]}
        onChange={e => setEmails(
          emails.map((email, j) => (i === j ? e.target.value : email))
        )}
      />
    </Grid>
  ))}
  <Fab className={classes.addButton} style={{ marginRight: 10, marginBottom: 10, backgroundColor: '#3B70BC', color: 'white' }} onClick={() => setEmails([...emails, ''])}> <Add /> </Fab>

 addButton: {
marginTop: theme.spacing.unit * 2,
color: '#3B70BC'
 }

答案 1 :(得分:0)

我可以使用下面的代码来使其工作。

  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();
    });
  });

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