在单元测试express node.js应用程序时,如何模拟redis?

dldeef67  于 2021-06-09  发布在  Redis
关注(0)|答案(0)|浏览(315)

我想对我的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};

所以现在我发现自己不知所措;被嘲笑、存根和依赖注入(在这里和其他测试中)弄糊涂了。我做错什么了?对这种功能进行单元测试的最佳方法是什么?

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题