typescript - 我如何开玩笑地模拟一个类的依赖关系
问题描述
我将如何模拟我正在用 jest 测试的类之一的依赖关系?
我有一个使用pigpio
模块的类
// a trimmed down version of the class and method I'm writing a test for
import { Gpio } from "pigpio"
export default class BotController {
private initializePenActuator(): void {
this.penPause = Number(process.env.PEN_PAUSE_DELAY_IN_MILLISECONDS)
this.penActuator = new Gpio(Number(process.env.PEN_ACTUATOR_PIN))
}
async setPenDirection(direction: penDirection, toggleAfterDelay?: boolean): Promise<void> {
return new Promise((resolve, reject) => {
this.penActuator.digitalWrite(direction) // the call I want to mock
if (!toggleAfterDelay) {
resolve()
}
setTimeout(() => {
resolve()
}, this.penPause)
})
}
}
我正在尝试为它编写以下测试:
test("can actuate with a delay", async () => {
// * actuate pen with a delay
const start: Date = new Date()
await controller.setPenDirection(penDirection.UP, true)
const end: Date = new Date()
const duration = end.getTime() - start.getTime()
// * confirm that the async call was delayed for the correct number of MS
expect(duration).toBeGreaterThanOrEqual(Number(process.env.PEN_PAUSE_DELAY_IN_MILLISECONDS))
})
但我不确定如何为 pigpio 方法调用编写模拟digitalWrite
。
我知道我可以创建一个类的模拟:
jest.mock("pigpio", () => {
return class {
digitalWrite(value) {}
}
})
但这会假设我在测试中直接调用 pigpio 类,而不是通过不同的类(对吗?)。
我一直在尝试阅读有关如何正确执行此操作的文档,但我似乎无法从示例中解析解决方案。如果不是很明显,我仍然对测试很满意。
我将如何模拟 pigpio 以便我可以测试我的班级的方法?
此外,如果您有指向我应该查看的文档中的位置的链接,我将不胜感激。我不知道我是否误解了我阅读的文档,或者我只是没有在开玩笑的文档中找到正确的位置:|
更新
在查看了 Estus 指出的文档中的自动模拟示例后,我看到了如何模拟该类的示例,如果该类是模块的默认导出。
https://jestjs.io/docs/en/es6-class-mocks#automatic-mock
但是,如果该类是模块的默认导出,则此示例有效。在我的情况下,该类不是默认导出:
如果我尝试只模拟模块,我会收到一个错误:
如果我尝试为模块模拟 Gpio 类,我仍然会收到错误消息:
而且我似乎无法在文档中找到正确执行此操作的示例:/
另一个更新
我还尝试为Gpio
该类创建一个模拟函数pigpio
,模拟模块并为该模拟提供一个使用模拟的实现,Gpio
但它仍然不起作用:
解决方案
太棒了,
我决定走依赖注入路线。我真的很想弄清楚如何在不走 DI 路线的情况下模拟 Gpio 类,但现在我只想继续前进。
类构造函数的依赖注入
那么,依赖注入应该相对容易吧?好吧,我试图做的依赖注入有一些障碍。我需要将该Gpio
类用作构造函数,而不是作为 Gpio 的实例。
在我BotController
的课堂上,我使用Gpio
该类来构造不同的实例Gpio
:
但是对于打字稿,如果你将一个类注入到构造函数中(我假设是方法),你不会得到类构造函数,你会得到一个类的实例。要注入构造函数而不是实例,您需要使用typeof
:
因为根据文档:
这里我们使用 typeof Greeter,即“给我 Greeter 类本身的类型”而不是实例类型。或者,更准确地说,“给我一个叫做 Greeter 的符号的类型”,它是构造函数的类型。
所以现在,我可以模拟pigpio
模块并将模拟的 Gpio 类传入以用作构造函数,并且测试不会崩溃。
明天,继续前进!!!!
更新
你有没有爬到山顶,疲惫而胜利地站在山顶,然后低头看到对面的自动扶梯?
发布此答案并上床睡觉后,我醒来后发现了 Estus 的另一条超级有用的评论:
你错过了 jest.mock 的 __esModule: true ,你需要它来命名 export 。没有它,一个 mock 被视为 CommonJS 模块,它转换为 ESM 默认导出。请参阅 jestjs.io/docs/en/...</p>
我在文档中没有看到任何关于此的内容,但是当您查看API 参考的给定部分时:
因此,有了这些新知识,我能够返回并将所有 BotController 代码更改回其原始状态,从而消除依赖注入:
在我的测试中,我将__esModule: true
设置添加回了模拟的实现,用模拟传回了我的Gpio
类模拟digitalWrite
,我的测试通过了:
我觉得我已经经历了敲门声,但最后我很高兴知道解决这个问题的几种方法。希望这个问题和答案中的细节可以避免其他人的头痛。
推荐阅读
- mongoose - 猫鼬将项目添加到数组
- javascript - 一个函数,它接受两个参数,一个数组和一个元素,它返回给定元素的索引
- javascript - 如何使用 JavaScript 创建用于打印的表格设计
- python - 如何在python上将.hex文件拆分为512字节
- reactjs - AWS Amplify React 构建失败模块解析失败:意外令牌 (1:0)
- jenkins-pipeline - 如何让 Jenkins 管道只为给定的分支构建
- python - 如何从两个数据框之间的合并中显示单个数据框的值?
- javascript - 后台脚本错误 - “错误:browser.tabs 未定义”
- python - 在 python 中使用函数更新 SQLite 列 DB
- python - 当我更新 self 变量时,一个奇怪的结果(因为我是 python 新手)。为什么会发生这种情况?