如何使用Jest测试异步存储?

Bri*_*ase 19 asynchronous reactjs jestjs react-native asyncstorage

我正在用React Native构建一个应用程序.我想尽量减少与数据库通信的频率,因此我大量使用AsyncStorage.但是DB和AsyncStorage之间的转换存在很多错误.因此,我想通过对它运行自动化测试来确保AsyncStorage拥有我相信它所做的数据.令人惊讶的是,我还没有找到任何有关如何在线进行此操作的信息.我试图独自完成这项工作并没有成功.

使用Jest:

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

此方法失败并显示错误:

TypeError: RCTAsyncStorage.multiGet is not a function
Run Code Online (Sandbox Code Playgroud)

删除返回将使其立即运行而无需等待值并不正确地通过测试.

当我尝试使用await关键字测试它时,我遇到了完全相同的错误:

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

有关如何成功运行AsyncStorage中的值断言的任何建议?我宁愿继续使用Jest,但如果它只能通过一些备用测试库来完成,我会对此持开放态度.

Yad*_*ran 22

也许你可以尝试这样的事情:

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)));
  });
}
Run Code Online (Sandbox Code Playgroud)

并在您的测试文件中:

import MockStorage from './MockStorage';

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

jest.setMock('AsyncStorage', AsyncStorage)

// ... do things
Run Code Online (Sandbox Code Playgroud)

  • 尽管尝试从 'react-native' 导入模块,但从 'myFileName.js' ' 获取 'Cannot find module 'AsyncStorage' - 有什么想法吗?:) (3认同)
  • 我使用这个答案作为解决方案,但我遇到了与@jhm 相同的问题。任何进展?谢谢。 (2认同)

Dav*_*llo 19

对于在> 2019中看到此问题的每个人:

20192月以来,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.
Run Code Online (Sandbox Code Playgroud)

新模块包括自己的模拟程序,因此您不必担心自己编写代码了。

根据项目的文档,您可以通过2种不同的方式进行设置:

与模拟目录

  • 在您的项目根目录中,创建一个__mocks__/@react-native-community目录。
  • 在该文件夹中,创建async-storage.js文件。
  • 在该文件中,导出异步存储模拟。
    export default from '@react-native-community/async-storage/jest/async-storage-mock'
    
    Run Code Online (Sandbox Code Playgroud) 然后AsyncStorage,默认情况下,Jest应该在所有测试中进行模拟。如果不是,请尝试jest.mock(@react-native-community/async-storage)在测试文件的顶部进行调用。

使用Jest安装文件

如果您使用的是TypeScript,那么使用第二个选项(Jest安装文件)会更容易,因为使用第一个选项(mocks目录)将不会@types/react-native-community__async-storage自动与模拟相关联。


jay*_*oby 10

我的原始答案只是指出了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']);
        });
    })
  }
}));
Run Code Online (Sandbox Code Playgroud)

我自己的模拟:

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());
        });
    })
  }
}));
Run Code Online (Sandbox Code Playgroud)

  • 由于 `const items = {}`:`jest.mock()' 的模块工厂不允许引用任何范围外的变量。无效的变量访问:items`。 (2认同)