web-dev-qa-db-ja.com

Jestで非同期ストレージをテストする方法は?

React Nativeを使用してアプリを構築しています。データベースと通信する頻度を最小限にしたいので、AsyncStorageを多用します。間の翻訳には多くのバグの余地があります。ただし、DBとAsyncStorageです。したがって、自動テストを実行して、AsyncStorageが信頼できるデータを持っていることを確認したいと思います。驚いたことに、オンラインでそれを行う方法に関する情報が見つかりませんでした。私自身はうまくいっていません。

Jestの使用:

it("can read asyncstorage", () => {
return AsyncStorage.getItem('foo').then(foo => {
  expect(foo).not.toBe("");
});  });

このメソッドはエラーで失敗しました:

TypeError: RCTAsyncStorage.multiGet is not a function

戻り値を削除すると、値を待たずに即座に実行され、テストに不合格となります。

Awaitキーワードを使用してテストしようとすると、まったく同じエラーが発生しました。

it('can read asyncstorage', async () => {
this.foo = "";
await AsyncStorage.getItem('foo').then(foo => {
    this.foo = foo;
});
expect(foo).not.toBe(""); });

AsyncStorageの値に対してアサーションを正常に実行する方法に関する提案はありますか?私はJestを使い続けたいと思いますが、それがいくつかの代替テストライブラリでしか実行できない場合は、私はそれを受け入れます。

22
Brian Case

私の最初の答えは、react-native-simple-storeの作者がいかにあざけることに対処したかを指摘しただけです。 Jasonのハードコーディングされた模擬応答を削除する独自のモックを使用して、回答を更新しました。

Jason Merinohttps://github.com/jasonmerino/react-native-simple-store/blob/master/tests/ index-test.js#L31-L64

jest.mock('react-native', () => ({
AsyncStorage: {
    setItem: jest.fn(() => {
        return new Promise((resolve, reject) => {
            resolve(null);
        });
    }),
    multiSet:  jest.fn(() => {
        return new Promise((resolve, reject) => {
            resolve(null);
        });
    }),
    getItem: jest.fn(() => {
        return new Promise((resolve, reject) => {
            resolve(JSON.stringify(getTestData()));
        });
    }),
    multiGet: jest.fn(() => {
        return new Promise((resolve, reject) => {
            resolve(multiGetTestData());
        });
    }),
    removeItem: jest.fn(() => {
        return new Promise((resolve, reject) => {
            resolve(null);
        });
    }),
    getAllKeys: jest.fn(() => {
        return new Promise((resolve) => {
            resolve(['one', 'two', 'three']);
        });
    })
  }
}));

私自身のモック:

const items = {};

jest.mock('react-native', () => ({

AsyncStorage: {        

    setItem: jest.fn((item, value) => {
        return new Promise((resolve, reject) => {        
    items[item] = value;
            resolve(value);
        });
    }),
    multiSet:  jest.fn((item, value) => {
        return new Promise((resolve, reject) => {
    items[item] = value;
            resolve(value);
        });
    }),
    getItem: jest.fn((item, value) => {
        return new Promise((resolve, reject) => {
            resolve(items[item]);
        });
    }),
    multiGet: jest.fn((item) => {
        return new Promise((resolve, reject) => {
            resolve(items[item]);
        });
    }),
    removeItem: jest.fn((item) => {
        return new Promise((resolve, reject) => {
            resolve(delete items[item]);
        });
    }),
    getAllKeys: jest.fn((items) => {
        return new Promise((resolve) => {
            resolve(items.keys());
        });
    })
  }
}));
9
jaygooby

あなたはこのようなことを試すことができるかもしれません:

mockStorage.js

export default class MockStorage {
  constructor(cache = {}) {
    this.storageCache = cache;
  }

  setItem = jest.fn((key, value) => {
    return new Promise((resolve, reject) => {
      return (typeof key !== 'string' || typeof value !== 'string')
        ? reject(new Error('key and value must be string'))
        : resolve(this.storageCache[key] = value);
    });
  });

  getItem = jest.fn((key) => {
    return new Promise((resolve) => {
      return this.storageCache.hasOwnProperty(key)
        ? resolve(this.storageCache[key])
        : resolve(null);
    });
  });

  removeItem = jest.fn((key) => {
    return new Promise((resolve, reject) => {
      return this.storageCache.hasOwnProperty(key)
        ? resolve(delete this.storageCache[key])
        : reject('No such key!');
    });
  });

  clear = jest.fn((key) => {
    return new Promise((resolve, reject) =>  resolve(this.storageCache = {}));
  });

  getAllKeys = jest.fn((key) => {
    return new Promise((resolve, reject) => resolve(Object.keys(this.storageCache)));
  });
}

そしてあなたの内部テストファイル

import MockStorage from './MockStorage';

const storageCache = {};
const AsyncStorage = new MockStorage(storageCache);

jest.setMock('AsyncStorage', AsyncStorage)

// ... do things
22
Yadhu Kiran

2019年以降にこの質問が表示されるすべての人:

2019年2月 以降、AsyncStorageは @ react-native-community/async-storageに移動されました、これは_react-native_からインポートする場合にこの警告を表示します。

_Warning: Async Storage has been extracted from react-native core and will be removed in a future release.
_

新しいモジュールには独自のモックが含まれているため、独自のモジュールを作成する必要はありません。

プロジェクトのドキュメントごとに 、2つの異なる方法で設定できます。

モックディレクトリ付き

  • プロジェクトのルートディレクトリに、___mocks__/@react-native-community_ディレクトリを作成します。
  • そのフォルダー内にasync-storage.jsファイルを作成します。
  • そのファイル内で、非同期ストレージモックをエクスポートします。
    _export default from '@react-native-community/async-storage/jest/async-storage-mock'
    _
    その後、JestはすべてのテストでデフォルトでAsyncStorageをモックする必要があります。そうでない場合は、テストファイルの先頭でjest.mock(@react-native-community/async-storage)を呼び出してみてください。

Jestセットアップファイル

  • Jest設定(おそらく_package.json_または_jest.config.js_)に、セットアップファイルの場所を追加します。
    _"jest": {
      "setupFiles": ["./path/to/jestSetupFile.js"]
    }
    _
  • セットアップファイル内で、AsyncStorageモックをセットアップします。

    _import mockAsyncStorage from '@react-native-community/async-storage/jest/async-storage-mock';
    
    jest.mock('@react-native-community/async-storage', () => mockAsyncStorage);
    _

TypeScriptを使用している場合、2番目のオプション(Jestセットアップファイル)を使用する方が簡単です。1番目のオプション(mocksディレクトリ)を使用すると、 t _@types/react-native-community__async-storage_をモックに自動的に関連付けます。

14
David Castillo

私は jest.setMock がこの場合jest.mockよりも良いので、react-nativeAsyncStorageを次のようにモックするだけで問題ありません。

jest.setMock('AsyncStorage', {
  getItem: jest.fn(
    item =>
      new Promise((resolve, reject) => {
        resolve({ myMockObjectToReturn: 'myMockObjectToReturn' });
      })
  ),
});
1
robertovg