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

时间:2016-12-03 21:13:09

标签: reactjs asynchronous react-native jestjs asyncstorage

我正在使用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,但如果它只能通过一些备用测试库来完成,我会对此持开放态度。

7 个答案:

答案 0 :(得分:8)

我的原始答案只是指出了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());
        });
    })
  }
}));

答案 1 :(得分:4)

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

February 2019起, 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.

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

Per the project's documentation,您可以通过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.jsonjest.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 ,则使用第二个选项(Jest安装文件)会更容易,因为使用第一个选项(mocks目录)不会将@types/react-native-community__async-storage与自动模拟。

答案 2 :(得分:0)

我认为jest.setMock在这种情况下可能比jest.mock更好,因此我们可以毫无疑问地使用react-native来模拟AsyncStorage,就像这样:

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

答案 3 :(得分:0)

使用以下命令安装模块: 从项目的根目录运行此命令。

npm install --save mock-async-storage

在项目根目录中,创建__mocks__\@react-native-community文件夹。在其中创建一个文件async-storage.js。 async-storage.js中的代码

export default from '@react-native-community/async-storage/jest/async-storage-mock'

在package.json内部配置笑话如下:

"jest": {
    "preset": "jest-expo",
    "transformIgnorePatterns" : ["/node_modules/@react-native-community/async-storage/(?!(lib))"]
  },

在这里,我正在使用jest-expo进行测试。如果您使用的是jest,则预设值为jest,而不是jest-expo。

在项目根目录中,创建一个名为jest.config.js的文件 jest.config.js文件中的配置:

module.exports = {
    setupFilesAfterEnv: [
      './setup-tests.js',
    ],
  };

在项目根目录中,创建一个名为setup-tests.js的文件。该文件中的代码是:

import MockAsyncStorage from 'mock-async-storage';

const mockImpl = new MockAsyncStorage();
jest.mock('@react-native-community/async-storage', () => mockImpl);

在项目根目录中创建测试文件。在这里,我称它为Example.test.js。

import  AsyncStorage  from '@react-native-community/async-storage';

beforeEach(() => {
    AsyncStorage.clear();
    // console.log(`After the data is being reset :`)
    // console.log(AsyncStorage)
});

it('can read asyncstorage', async () => {

    await AsyncStorage.setItem('username', 'testUser')
    let usernameValue = await AsyncStorage.getItem('username')
    // console.log(`After the data is being set :`)
    // console.log(AsyncStorage)
    expect(usernameValue).toBe('testUser')
});

在此处使用AsyncStorage.setItem将用户名的值设置为testUser。然后使用getItem函数获取值。 测试用例是比较usernameValue是否等于testUser。 如果是,则测试用例通过,否则测试用例将失败。

使用beforeEach以便每次运行测试用例时,Asyncstorage都会被清除并且为空。 如果需要,可以使用console.log

检查Asyncstorage中的内容。

运行命令 yarn test 来运行测试。输出为:

enter image description here

答案 4 :(得分:0)

我刚刚在最新版本的 Expo 上运行 jest 时遇到了这个问题,并按照 https://react-native-async-storage.github.io/async-storage/docs/advanced/jest/ 上的说明中的“jest setup file”选项解决了这个问题。

请注意,AsyncStorage 已(无论出于何种原因)重命名\移回“@react-native-async-storage/async-storage”,并且其包名称中不再包含“community”。

答案 5 :(得分:0)

1- 在根项目中添加文件夹 __mocks__

2- 在 @react-native-async-storage 文件夹中添加文件夹 __mocks__

3- 在 async-storage.js 中添加文件 @react-native-async-storage

4- 添加代码:

let db = {};

export default {
    setItem: (item, value) => {
        return new Promise((resolve, reject) => {
            db[item] = value;
            resolve(value);
        });
    },
    multiSet: (item, fun) => {
        return new Promise((resolve, reject) => {
            for (let index = 0; index < item.length; index++) {
                db[item[index][0]] = item[index][1];
            }
            fun()
            resolve(value);
        });
    },
    getItem: (item, value= null) => {
        return new Promise((resolve, reject) => {
            resolve(db[item]);
        });
    },
    multiGet: (item) => {
        return new Promise((resolve, reject) => {
            resolve(db[item]);
        });
    },
    removeItem: (item) => {
        return new Promise((resolve, reject) => {
            resolve(delete db[item]);
        });
    },
    getAllKeys: (db) => {
        return new Promise((resolve) => {
            resolve(db.keys());
        });
    }
}

答案 6 :(得分:-1)

对于其他任何人来说,asyncStorage也需要一个回调,一些libs使用这个