应用程序启动时,它将实例化Redis客户端对象:
const redisClient = redis.createClient(REDIS_URL);
我维护一个代理对象myRedisClient
,该对象公开了客户端对象公开的API的承诺版本:
const get = (key) =>
new Promise((resolve, reject) =>
redisClient.get(key, (err, resp) =>
err ? reject(err) : resolve(resp))
const myRedisClient = { get };
简单地隐式实例化redisClient
感觉是错误的,因此我想将其放在显式调用的方法中:
let redisClient = null;
const init = () => redisClient || redis.createClient(REDIS_URL);
const myRedisClient = { init, get};
get
需要访问redisClient
。如果get
与redisClient
变量位于同一文件中,则很简单。
但是,如果get
在单独的文件中,则可以通过关闭redisClient
并将redisClient
作为get
的自变量来使其可用。
// my-redis-client.js
import get from './get';
let redisClient = null;
const init = () => redisClient || redis.createClient(REDIS_URL);
const myRedisClient = { init, get(key) => get(redisClient, key) };
// get.js
const get = (redisClient, key) =>
new Promise((resolve, reject) =>
redisClient.get(key, (err, resp) =>
err ? reject(err) : resolve(resp));
最后,我希望能够存根redisClient
,并且我想然后可以从redis.createClient
存根createCheckboxes = () => {
return this.availableSizes.map((size) => {
return < Size size={size}/>
});
}
(例如,使用测试运行器中内置的存根功能)。测试。
这是否听起来很理智?
答案 0 :(得分:1)
仅隐式实例化
redisClient
感觉不对
不,这没什么问题,这正是您的应用在启动时应该做的事情。
redisClient
的问题在于,它是一个有状态的全局变量,而您的myRedisClient
隐含地依赖。将redisClient
的初始化放在要显式调用的方法中并不能解决这些问题。
要能够存根redisClient
global.redisClient = …
来明确指出它是一个全局变量。对于模拟,您可以轻松地覆盖全局(如果您不想使用独立的模拟并行运行多个测试)。myRedisClient.js
依赖于redisClient.js
模块的模块系统,该模块导出“全局”静态值,但让您的测试系统使用带有依赖项注入的模块加载器myRedisClient
创建一个构造函数或工厂函数,以便您可以通过将redisClient
显式传递给它来对其进行初始化。最后一个解决方案似乎符合您尝试做的事情。它应该看起来像这样:
// my-redis-client.js
default export function init(redisClient) {
const get = util.promisify(redisClient.get).bind(redisClient);
return { get };
}
// main.js
import initMyClient from 'my-redis-client'
const myRedisClient = initMyClient(redis.createClient(REDIS_URL));