Pau*_*oyd 5 javascript unit-testing mocking redis node.js
我想对我的 Express 应用程序进行单元测试,其中部分内容从 Redis 数据库设置和获取数据。调查为什么我的一些测试间歇性失败 \xe2\x80\x94 并且随着我继续开发我的应用程序 \xe2\x80\x94 更频繁地失败,我意识到我的测试仍然调用 Redis 服务器,而不是我认为我嘲笑过的服务器记忆。
\n\n如何成功模拟 Redis 客户端 (ioredis),以便可以相互隔离地对部分代码进行单元测试,而无需调用 Redis 服务器?
\n\n这是我到目前为止所拥有的。
\n\n我有一个应用程序模型,它将 package.json 中的值与 Redis 数据库中的值合并,通常带有后备值。可以添加或检索值。
\n\n// models/application.js\n\nimport fs from \'fs\';\nimport {client} from \'../config/database.js\';\n\nexport const getAll = async () => {\n const data = await client.hgetall(\'application\');\n const package_ = JSON.parse(fs.readFileSync(\'package.json\'));\n\n const application = {\n name: data.name || \'IndieKit\',\n version: package_.version,\n description: package_.description,\n repository: package_.repository,\n locale: data.locale || \'en\',\n themeColor: data.themeColor || \'#0000ee\'\n };\n\n return application;\n};\n\nexport const get = async key => {\n const application = await getAll();\n return application[key];\n};\n\nexport const setAll = async values => {\n return client.hmset(\'application\', values);\n};\n\nexport const set = async (key, value) => {\n return client.hset(\'application\', key, value);\n};\nRun Code Online (Sandbox Code Playgroud)\n\nclient从一个单独的文件调用,我在其中使用ioredis连接到 Redis 服务器:
// config/database.js\n\nimport Redis from \'ioredis\';\n\nexport const client = new Redis(process.env.REDIS_URL);\nexport const expires = 3600;\n\nclient.on(\'error\', error => {\n console.error(\'Redis\', error);\n});\nRun Code Online (Sandbox Code Playgroud)\n\n我\xe2\x80\x99m使用Ava作为我的测试框架,使用rewiremock用ioredis-mock \xe2\x80\xa6\xc2\xa0替换ioredis依赖,或者我想!
\n\n// tests/models/application.js\n\nimport test from \'ava\';\nimport {rewiremock} from \'../helpers/rewiremock.js\';\nimport {client} from \'../../config/database.js\';\n\ntest.beforeEach(async t => {\n t.context.applicationModel = await rewiremock.proxy(() => {\n return import(\'../../models/application.js\');\n });\n});\n\ntest.afterEach.always(() => {\n client.flushall();\n});\n\ntest.serial(\'Gets a value\', async t => {\n await t.context.applicationModel.set(\'name\', \'foobar1\');\n const result = await t.context.applicationModel.get(\'name\');\n t.is(result, \'foobar1\');\n});\n\ntest.serial(\'Gets all values\', async t => {\n await t.context.applicationModel.set(\'name\', \'foobar2\');\n const result = await t.context.applicationModel.getAll();\n t.is(result.name, \'foobar2\');\n});\n\ntest.serial(\'Sets a value\', async t => {\n await t.context.applicationModel.set(\'name\', \'foobar3\');\n const result = await t.context.applicationModel.get(\'name\');\n t.is(result, \'foobar3\');\n});\n\ntest.serial(\'Sets all values\', async t => {\n await t.context.applicationModel.setAll({\n name: \'foobar4\',\n locale: \'bazqux1\'\n });\n const result = await t.context.applicationModel.getAll();\n t.is(result.name, \'foobar4\');\n t.is(result.locale, \'bazqux1\');\n});\nRun Code Online (Sandbox Code Playgroud)\n\n现在再看一遍,显然存在几个问题。首先,我在 上执行一条flushAll命令client,该命令直接与 Redis 服务器交互,而不是与内存中的模拟服务器交互。其次,需要为每个测试使用不同的值应该提醒我有什么问题;如果我在每次测试后真正刷新数据库,我就不需要这个了。
这里\xe2\x80\x99s rewiremock helper I\xe2\x80\x99m 导入到这个测试中:
\n\nimport rewiremock from \'rewiremock/node.js\';\n\nrewiremock(\'ioredis\')\n .by(\'ioredis-mock\');\n\nexport {rewiremock};\nRun Code Online (Sandbox Code Playgroud)\n\n所以现在我发现自己很茫然;对模拟、存根和依赖注入(在这里和其他测试中)感到困惑和困惑。我究竟做错了什么?对此类功能进行单元测试的最佳方法是什么?
\n| 归档时间: |
|
| 查看次数: |
2476 次 |
| 最近记录: |