我想对我的express应用程序进行单元测试,其中的一部分从redis数据库中设置和获取数据。在调查为什么我的一些测试会间歇性地失败——而且在我继续开发应用程序的过程中会更频繁地失败——我意识到,我的测试仍然调用redis服务器,而不是我认为在内存中嘲笑过的服务器。
如何成功地模拟redis客户机(ioredis),以便在不调用redis服务器的情况下独立地单元测试代码的各个部分?
这是我到目前为止的情况。
测试中的代码
我有一个应用程序模型,它将package.json中的值与我的redis数据库中的值合并在一起,通常还带有回退值。可以添加或检索值。
// models/application.js
import fs from 'fs';
import {client} from '../config/database.js';
export const getAll = async () => {
const data = await client.hgetall('application');
const package_ = JSON.parse(fs.readFileSync('package.json'));
const application = {
name: data.name || 'IndieKit',
version: package_.version,
description: package_.description,
repository: package_.repository,
locale: data.locale || 'en',
themeColor: data.themeColor || '#0000ee'
};
return application;
};
export const get = async key => {
const application = await getAll();
return application[key];
};
export const setAll = async values => {
return client.hmset('application', values);
};
export const set = async (key, value) => {
return client.hset('application', key, value);
};
``` `client` 从单独的文件调用,在该文件中,我使用ioredis连接到redis服务器:
// config/database.js
import Redis from 'ioredis';
export const client = new Redis(process.env.REDIS_URL);
export const expires = 3600;
client.on('error', error => {
console.error('Redis', error);
});
### 试验
我使用ava作为我的测试框架,用rewiremock用ioredis mock替换ioredis依赖… 或者我是这么想的!
// tests/models/application.js
import test from 'ava';
import {rewiremock} from '../helpers/rewiremock.js';
import {client} from '../../config/database.js';
test.beforeEach(async t => {
t.context.applicationModel = await rewiremock.proxy(() => {
return import('../../models/application.js');
});
});
test.afterEach.always(() => {
client.flushall();
});
test.serial('Gets a value', async t => {
await t.context.applicationModel.set('name', 'foobar1');
const result = await t.context.applicationModel.get('name');
t.is(result, 'foobar1');
});
test.serial('Gets all values', async t => {
await t.context.applicationModel.set('name', 'foobar2');
const result = await t.context.applicationModel.getAll();
t.is(result.name, 'foobar2');
});
test.serial('Sets a value', async t => {
await t.context.applicationModel.set('name', 'foobar3');
const result = await t.context.applicationModel.get('name');
t.is(result, 'foobar3');
});
test.serial('Sets all values', async t => {
await t.context.applicationModel.setAll({
name: 'foobar4',
locale: 'bazqux1'
});
const result = await t.context.applicationModel.getAll();
t.is(result.name, 'foobar4');
t.is(result.locale, 'bazqux1');
});
现在再看看这个,显然有几个问题。首先,我在表演 `flushAll` 命令开启 `client` ,它直接与redis服务器交互,而不是内存中的模拟服务器。其次,每次测试都需要使用不同的值,这应该提醒我出了什么问题;如果每次测试后都要刷新数据库,我就不需要这样做了。
下面是我要导入到这个测试中的rewiremock助手:
import rewiremock from 'rewiremock/node.js';
rewiremock('ioredis')
.by('ioredis-mock');
export {rewiremock};
所以现在我发现自己不知所措;被嘲笑、存根和依赖注入(在这里和其他测试中)弄糊涂了。我做错什么了?对这种功能进行单元测试的最佳方法是什么?
暂无答案!
目前还没有任何答案,快来回答吧!