javascript - Sinon 如何对非导出的私有功能进行单元测试?
问题描述
我对单元测试真的很陌生,我试图使用 模拟aws.ses
方法sinon.js
,但我关心的是我如何调用该sesConstructor
方法。由于它没有从 导出,我在测试套件中ses.js
声明了一个方法。sesConstructor
如果有人能告诉我这是否是一个完整的反模式以及是否有任何其他更好的解决方案(不使用'rewire'模块),我将不胜感激
ses.js
let ses = {};
const sesConstructor = () => {
AWS.config.update({
accessKeyId: configurations.AWS_CONFIG.ACCESSKEYID,
secretAccessKey: configurations.AWS_CONFIG.SECRECTACCESSKEY,
region: configurations.AWS_CONFIG.REGION
});
ses = new AWS.SES({ apiVersion: "2010-12-01" });
};
export const sendTemplatedEmail = (emailTo, templateName, templateData) => {
sesConstructor();
const params = {
Destination: {
ToAddresses: emailTo
},
Source: process.env.emailSource,
Template: templateName,
TemplateData: JSON.stringify(templateData)
};
return ses.sendTemplatedEmail(params).promise();
};
export default { sendTemplatedEmail };
ses.test.js
describe("SES", () => {
const emailTo = ["test@gmail.com"];
const templateName = "template";
const templateData = "test";
process.env.emailSource = "test@gamil.com";
const sendEmail = sendTemplatedEmail(emailTo, templateName, templateData);
it("should return a promise", () => {
expect(sendEmail).to.be.a("promise");
});
describe("sesConstructor", () => {
it("should call AWS SES", () => {
const sesConstructor = data => {
const ses = new AWS.SES(data); // eslint-disable-line no-unused-vars
};
const mockAWS = sinon.mock(AWS);
mockAWS
.expects("SES")
.once()
.withArgs({
apiVersion: "2010-12-01"
})
.returns(true);
sesConstructor({ apiVersion: "2010-12-01" });
mockAWS.verify();
mockAWS.restore();
});
});
});
解决方案
实际上,您的sendTemplatedEmail
函数还做了一件未在名称中指明的事情:初始化传输。并且很难依赖sendTemplatedEmail
. 您需要与此依赖项有关,以使其更具可测试性,可能的解决方案:
1) 将传输实例作为参数传递。考虑下一个:
const sesConstructor = () => {
//...
return AWS.SES(...);
};
export const sendTemplatedEmail = (emailTo, templateName, templateData, ses = sesConstructor()) => {
const params = {...}
return ses.send(...);
}
在这种情况下,您将新参数添加到您的sendTemplatedEmail
ses 实例中,默认情况下来自sesConstructor()
- 这允许您在测试中传递存根,并轻松测试它。
closure
如果它适合您,您也可以将实例放入:
export const sendTemplatedEmail = (ses = sesConstructor()) => (emailTo, templateName, templateData) => {
const params = {...}
return ses.send(...)
}
然后你会使用它:
sendTemplatedEmail()('some@person.com'...)
并在测试中将存根传递给它,并轻松测试它:
sendTemplatedEmail(stubOfSes)('some@person.com'...)
dependency injection
如果您需要更多关于它的理论,请谷歌。
2)导出它。为什么不使用 2 个道具导出对象:sesConstructor
和sendTemplatedEmail
?
let emailSender = {
sesConstructor: () => {
//...
return AWS.SES(...);
},
sendTemplatedEmail: (emailTo, templateName, templateData) => {
// ...
return this.sesConstructor().sendTemplatedEmail(...);
};
export default emailSender;
在这种情况下,在您的测试文件中,您只需要存根sesConstructor
导入对象的方法,并使其易于测试。
我不认为它是如何组织它的完整列表,但这是我将使用它的方向。
希望能帮助到你。
推荐阅读
- visual-studio-code - 如何找到我在 VS Code 中使用的主题的文件夹
- python - 是否可以在不锁定的情况下与 NamespaceProxy 和 BaseManager 共享复杂对象?
- google-apps-script - 在谷歌应用脚本中设置计时器
- swift - 动态单元格的高度 - SWIFT
- javascript - voxeet/dolby.io 生成多个会议
- php - 更改woocommerce'优惠券不存在!错误信息
- javascript - JavaScript 类实例与静态
- javascript - 如果 jquery 自动完成返回结果,则禁用按钮
- typescript - 如何为可以访问 Vuex this.$store 的 Vue.js 创建一个 Utils 类
- javascript - 如何在 JavaScript 中的 Chart js 下为多轴循环?