【问题标题】:Jasmine Testing Constructor That has a Promise有 Promise 的 Jasmine 测试构造函数
【发布时间】:2019-06-11 02:56:52
【问题描述】:

我有一个充当数据存储的服务。在它的构造函数中,它尝试从设备的存储中“水合”数据集(使用 Ionic 并且它是 Storage 服务):

@Injectable()
export class SimpleDataStore {

     private _data: BehaviorSubject<any> = new BehaviorSubject<any>(undefined);
     public data: Observable<any> = this._data.asObservable();

     constructor(private _http: HttpClient, private _storage) {
         this.initializeData();
     }

     private initializeData(): void {
          this._storage.get("dataKey")
              .then(data => this._data.next(data))
              .catch(() => this._data.next([]);
     }

}

我知道如何使用 Jasmine 编写异步测试,以及如何访问私有成员/方法,并且知道需要检查 _data.getValue() 以获得我想要的结果——但我的问题是不知道如何测试:

  1. 构造函数,和/或;
  2. initializeData 以便它等待 Promise 完成,因为该方法中没有返回 Promise。

感谢您的帮助!

【问题讨论】:

  • 如果您模拟_storage 实现,您可以控制this._storage.get("dataKey") 何时解析,您是否尝试过这样做?
  • 我有——就像spyOn(TestBed.get(Storage), 'get').and.returnValue(Promise.resolve(localStorage));。但是如果没有将测试方法设置为async - 我真的不能,因为没有返回任何承诺,我有点迷路了。

标签: angular jasmine angular-test


【解决方案1】:

理想情况下,您应该让initializeData() 返回它构造的承诺,以便您可以轻松地等待它在您的测试中解决。然后,您可以在构造类之前简单地模拟initializeData(),而不是试图弄清楚承诺何时解决。

鉴于 initializeData() 方法已更改为返回承诺,您可以按如下方式测试 SimpleDataStore 类:

describe('SimpleDataStore', function () {

    beforeEach(function () {
        this.initializeData = spyOn(SimpleDataStore.prototype, 'initializeData');
        this.http = jasmine.createSpyObj('HttpClient', ['get']);
        this.storage = jasmine.createSpyObj('Storage', ['get']);
        this.dataStore = new SimpleDataStore(this.http, this.storage);

        // initializeData is called immediately upon construction.
        expect(this.initializeData).toHaveBeenCalled();
    });

    describe('initializeData', function () {

        beforeEach(function () {
            // The data store is initialized, we can now let the calls go to the real implementation.
            this.initializeData.and.callThrough();
        });

        afterEach(function () {
            expect(this.storage.get).toHaveBeenCalledWith('dataKey');
        });

        it('is initialized with "dataKey" storage', function (done) {
            const data = {};
            this.storage.get.and.returnValue(Promise.resolve(data));
            this.dataStore.initializeData()
                .then(() => expect(this.dataStore._data.getValue()).toBe(data))
                .catch(fail)
                .finally(done)
        });

        it('is initialized with empty array when "dataKey" storage rejects', function (done) {
            this.storage.get.and.returnValue(Promise.reject());
            this.dataStore.initializeData()
                .then(() => expect(this.dataStore._data.getValue()).toEqual([]))
                .catch(fail)
                .finally(done)
        });

    });

});

【讨论】:

  • 非常感谢——我原以为这是可用的选项,但不确定是否有任何副作用我会因为让该方法返回 Promise 而丢失。
  • 解决方案并不完美,但它确实有效。如果你真的想避免副作用,你可以引入工厂模式,工厂可以做检查“存储”的异步工作,然后与结果同步构造对象。
猜你喜欢
  • 2022-01-24
  • 2017-01-16
  • 2019-05-02
  • 2015-09-18
  • 2012-12-29
  • 2013-09-28
  • 2013-11-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多