简体   繁体   English

离子存储 v3 - 单元测试 | 类型错误:_this.storage.forEach 不是 function

[英]Ionic Storage v3 - Unit Tests | TypeError: _this.storage.forEach is not a function

I have a StorageService wrapper for @ionic/storage-angular where I have a function that looks roughly like this:我有一个用于@ionic/storage-angularStorageService包装器,其中我有一个 function,大致如下所示:

import { Injectable } from '@angular/core';
import { Storage } from '@ionic/storage-angular';

@Injectable({
  providedIn: 'root'
})
export class StorageService {
  constructor(public storage: Storage) {}

  async getData() {
    const data = [];
    await this.initStorage();

    return new Promise((resolve) => {
      this.storage
        .forEach((value, key) => {
          if (key.startsWith('data-')) {
            data.push({
              key: 'someKey,
              value,
            });
          }
        })
        .then(() => resolve(data));
    });
  }

  // other functions here
}

I have a unit test that looks like this我有一个看起来像这样的单元测试

import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { fakeAsync, flush, TestBed } from '@angular/core/testing';
import { StorageService } from './storage.service';
import { Storage } from '@ionic/storage-angular';


describe('StorageService', () => {
  let service: StorageService;
  let mockStorage: jasmine.SpyObj<Storage>;

  beforeEach(() => {
    mockStorage = jasmine.createSpyObj('Storage', ['get', 'set', 'remove', 'create']);

    TestBed.configureTestingModule({
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
      providers: [
        { provide: Storage, useValue: mockStorage },
      ],
    });
    service = TestBed.inject(StorageService);
  });

  describe('getData()', () => {
    it('should call StorageService.initStorage()', fakeAsync(() => {
      spyOn<any>(service, 'initStorage').and.stub();

      service.getData();
      flush();

      expect(service['initStorage']).toHaveBeenCalled();
    }));
  });

  // other tests here
});

It fails with它失败了

Error: Uncaught (in promise): TypeError: _this.storage.forEach is not a function
        TypeError: _this.storage.forEach is not a function

Storage itself is supposed to be iterable yet jasmine doesn't see it as such because of the way I mocked it, I assume.存储本身应该是可迭代的,但 jasmine 并不认为它是因为我嘲笑它的方式,我假设。

The question is: how do I unit test this bit correctly?问题是:我如何正确地对这个位进行单元测试? I don't want to create a real storage instance for testing purposes, is there a way to define this.storage as iterable via mocks?我不想为测试目的创建一个真实的存储实例,有没有办法通过模拟将 this.storage 定义为可迭代的?

It seems that Storage is an array.似乎Storage是一个数组。

Try this for a quick unblock:试试这个快速解锁:

providers: [
        { provide: Storage, useValue: [] },
      ],

We are providing an empty array for Storage because we are doing this.storage.forEach( . You can modify this array to your liking.我们正在为Storage提供一个空数组,因为我们正在执行this.storage.forEach( 。您可以根据自己的喜好修改此数组。

Answering my own questions again.再次回答我自己的问题。

My goal was to both preserve my spy object to mock storage.get and storage.set and be able to test storage.forEach .我的目标是保留我的间谍 object 以模拟storage.getstorage.set并能够测试storage.forEach That doesn't seem to be possible.这似乎是不可能的。 The answer above may suit those who only need to test storage.forEach .上面的答案可能适合那些只需要测试storage.forEach的人。

I resorted to not using storage.forEach at all and instead I iterate through storage.keys like this:我根本不使用storage.forEach ,而是像这样遍历storage.keys

async getData(): Promise<Array<{key: string, value}>> {
    await this.initStorage();

    return this.storage.keys()
      .then(keys => Promise.all(keys
        .filter(key => key.startsWith('data-'))
        .map(async key => {
          const value = await this.storage.get(key);

          return {
            key: 'someKey',
            value,
          }
        })
      ));
  }

This yields the same result and is much easier to test.这会产生相同的结果并且更容易测试。 I just needed to add the keys method to my existing spy like this:我只需要像这样将 keys 方法添加到我现有的间谍中:

mockStorage = jasmine.createSpyObj('Storage', ['get', 'set', 'remove', 'create', 'keys']);

and then mock the return value然后模拟返回值

mockStorage.keys.and.resolveTo(['different', 'storage', 'keys']);

It's rather straightforward from there.从那里开始相当简单。 Hope this helps someone in the future.希望这对将来的人有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM