【问题标题】:Angular 2+ Promise Unit testingAngular 2+ Promise 单元测试
【发布时间】:2018-04-11 20:40:19
【问题描述】:

您好,我正在尝试为以下 Angular 服务编写 jasmine 单元测试。

但是,我在为如何编写返回承诺值的测试而苦苦挣扎,并且无法找到任何详细的资源如何为这些情况编写。

大部分困难来自于不知道如何测试返回的承诺中调用的内容。

例如,我想测试调用this.createMap() 调用this._mapResolver 与地图实例new google.maps.Map(el, mapOptions)

Angular 2+ 的专家能否帮助我理解 Promise 的编写规范?或者可以借鉴的参考资料?

declare let google: any;

/**
 * Wrapper class that handles the communication with the Google Maps Javascript
 * API v3
 */
@Injectable()
export class GoogleMapsAPIWrapper {
  private _map: Promise<mapTypes.GoogleMap>;
  private _mapResolver: (value?: mapTypes.GoogleMap) => void;

  constructor(private _loader: MapsAPILoader, private _zone: NgZone) {
    this._map =
      new Promise<mapTypes.GoogleMap>((resolve: () => void) => { this._mapResolver = resolve; });
  }

  createMap(el: HTMLElement, mapOptions: mapTypes.MapOptions): Promise<void> {
    return this._loader.load().then(() => {
      const map = new google.maps.Map(el, mapOptions);
      this._mapResolver(<mapTypes.GoogleMap>map);
      return;
    });
  }

  setMapOptions(options: mapTypes.MapOptions) {
    this._map.then((m: mapTypes.GoogleMap) => { m.setOptions(options); });
  }
}

@ArmenVardanyan 建议的解决方案

describe('Service: GoogleMapsAPIWrapper', () => {

  const loaderServiceStub = {
    load: () => Promise.resolve()
  };

  let service;


  beforeEach(async(() => {
    TestBed.configureTestingModule({
      providers: [
        GoogleMapsAPIWrapper,
        {provide: MapsAPILoader, useValue: loaderServiceStub}
      ]
    });
  }));

  beforeEach(async(inject([GoogleMapsAPIWrapper], (_service: GoogleMapsAPIWrapper) => {
    service = _service;
  })));


  it('should be created',() => {
    expect(service).toBeTruthy();
  });

  it('should be call _mapResolver with specified arguments', async(() => {
    const elem = document.createElement('div');
    const spyOnCreateMap = spyOn(service, '_mapResolver');
    service.createMap(elem, {})
      .then(() => {
        expect(spyOnCreateMap).toHaveBeenCalled();
        expect(spyOnCreateMap).toHaveBeenCalledWith(new google.maps.Map(elem, {}));
      });
  }));

});

【问题讨论】:

  • 您到底想测试什么? Google Maps API 真的有效吗?或者如果方法真的返回 Promises?
  • @ArmenVardanyan 感谢您的回复。对于 createMap() 方法,我想检查是否使用正确的参数调用了 this._mapResolver。对于 setMapOptions() 方法,我想检查是否使用(选项)调用了 m.setOptions。我已经检查过 google maps api 实际上在其他文件中工作。
  • 好的,我会尽量提供答案

标签: javascript angular unit-testing jasmine


【解决方案1】:

我不记得如何正确注入 NgZone int 测试,但我认为这与您的问题无关。所以你只需要模拟 MapsAPILoader 服务并测试_mapResolver

const loaderServiceStub = {
  load: () => Promise.resolve()
};

describe('GoogleMapsAPIWrapper', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        GoogleMapsAPIWrapper,
        {provide: MapsAPILoader, useValue: loaderServiceStub}
      ]
    });
  });

  it('should be created', inject([GoogleMapsAPIWrapper], (service: GoogleMapsAPIWrapper) => {
    expect(service).toBeTruthy();
  }));

  it('should be call _mapResolver with specified arguments', inject([GoogleMapsAPIWrapper], (service: GoogleMapsAPIWrapper) => {
    const spyOnCreateMap = spyOn(service, '_mapResolver');
    service.createMap(new HTMLDivElement(), {/*options */});
    expect(spyOnCreateMap).toHaveBeenCalled();
  }));
});

所以你基本上模拟了加载器服务,只在调用 load 时返回一个已解析的 Promise,然后检查是否调用了 _mapResolver。但是您无法检查提供的参数是否正确,因为这几行:

const map = new google.maps.Map(el, mapOptions);
this._mapResolver(<mapTypes.GoogleMap>map);

在传递给then 方法的回调中创建了一个映射,但您无法知道该对象将是什么。你可以试试

expect(spyOnCreateMap).toHaveBeenCalledWith(new google.maps.Map(el, mapOptions));

但我几乎可以肯定它不会起作用。您要编写的第二个测试也存在同样的问题:_map 承诺将返回一个具有setOptions 方法的对象,但您并不真正知道该对象将是什么。否则,您将不得不模拟该 Promise,然后确保已调用模拟的 setOptions 方法。

【讨论】:

  • toHaveBeenCalledWith 也能正常工作,但我必须用 async() 包装 it 回调
猜你喜欢
  • 2017-01-13
  • 2017-03-22
  • 2021-12-23
  • 2016-12-29
  • 2017-06-28
  • 1970-01-01
  • 1970-01-01
  • 2017-06-03
相关资源
最近更新 更多