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

dfuffjeb  于 2022-12-08  发布在  Jest
关注(0)|答案(7)|浏览(193)

我正在使用ReactNative构建一个应用程序。我希望最大限度地减少与数据库通信的频率,因此我大量使用AsyncStorage。不过,在DB和AsyncStorage之间的转换中存在很多漏洞。因此,我希望通过对AsyncStorage运行自动测试来确保它拥有我认为它拥有的数据。令人惊讶的是,我还没有在网上找到任何关于如何做到这一点的信息。我试图自己做这件事还没有成功。
使用笑话:

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中的值运行Assert,有什么建议吗?我更喜欢继续使用Jest,但是如果只能使用一些替代的测试库来完成,我也愿意接受。

qyzbxkaa

qyzbxkaa1#

对于每一个在〉2019中看到这个问题的人:
由于Nov 2020AsyncStorage被重新命名为@react-native-async-storage/async-storage”,如果您从react-native导入它,则会出现以下警告:

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

新模块包含自己的mock,因此您不必再担心编写自己的mock。
Per the project's documentation,您可以通过两种不同的方式进行设置:

使用模拟目录

  • 在项目根目录中,创建一个__mocks__/@react-native-community目录。
  • 在该文件夹中,创建async-storage.js文件。
  • 在该文件中,导出异步存储mock.
export default from '@react-native-async-storage/async-storage/jest/async-storage-mock'

Jest应该在所有测试中默认模拟AsyncStorage,如果没有,尝试在测试文件顶部调用jest.mock(@react-native-async-storage/async-storage)

使用Jest安装文件

  • 在Jest配置中(可能在package.jsonjest.config.js中)添加安装文件的位置:
"jest": {
  "setupFiles": ["./path/to/jestSetupFile.js"]
}
  • 在安装文件中,设置AsyncStorage模拟:
import mockAsyncStorage from '@react-native-async-storage/async-storage/jest/async-storage-mock';

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

如果您使用TypeScript,则使用第二个选项(Jest安装文件)要容易得多,因为使用第一个选项(mocks目录)时,它不会自动将@types/react-native-community__async-storage与mock关联。

xlpyo6sf

xlpyo6sf2#

也许你可以试试这样的办法:

模拟存储.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
fafcakar

fafcakar3#

我最初的回答只是指出了react-native-simple-store的作者是如何处理嘲笑的,我用我自己的嘲笑来更新我的回答,删除了杰森硬编码的嘲笑回应。
Jason Merino在www.example.com中提供了一种非常简单的方法https://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());
        });
    })
  }
}));
xeufq47z

xeufq47z4#

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

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:

"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将username的值设置为testUser。然后使用getItem函数获取该值。该测试用例用于比较usernameValue是否等于testUser。如果是,则测试用例通过,否则测试用例将失败。
使用beforeEach,以便每次运行测试用例时,Asyncstorage都被清除并为空。如果需要,可以使用console.log检查Asyncstorage中存在的内容
运行命令 yarn test 以运行测试。输出为:

mo49yndu

mo49yndu5#

我认为jest.setMock在这种情况下可能比jest.mock更好,所以我们可以使用react-native,没有问题,只是像这样模拟AsyncStorage

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

wsewodh26#

我刚刚遇到这个问题运行jest与最新版本的博览会,并解决了它以下的“jest安装文件”选项的方向在https://react-native-async-storage.github.io/async-storage/docs/advanced/jest/
请注意,AsyncStorage(无论出于何种原因)已重命名\移回“@react-native-async-storage/async-storage”,并且其软件包名称中不再包含“community”。

sq1bmfud

sq1bmfud7#

1-在根项目中添加文件夹__mocks__
2-在__mocks__文件夹中添加文件夹@react-native-async-storage
3-在@react-native-async-storage中添加文件async-storage.js
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());
        });
    }
}

相关问题