我正在尝试使用jest来模拟课程Mailer
而我无法弄清楚如何去做。文档没有提供很多有关其工作原理的示例。该过程是我将触发一个节点事件password-reset
,当该事件被触发时,我想使用Mailer.send(to, subject, body)
发送电子邮件。这是我的目录结构:
project_root
-- __test__
---- server
------ services
-------- emails
---------- mailer.test.js
-- server
---- services
------ emails
-------- mailer.js
-------- __mocks__
---------- mailer.js
这是我的模拟文件__mocks__/mailer.js
:
const Mailer = jest.genMockFromModule('Mailer');
function send(to, subject, body) {
return { to, subject, body };
}
module.exports = Mailer;
和我的mailer.test.js
const EventEmitter = require('events');
const Mailer = jest.mock('../../../../server/services/emails/mailer');
test('sends an email when the password-reset event is fired', () => {
const send = Mailer.send();
const event = new EventEmitter();
event.emit('password-reset');
expect(send).toHaveBeenCalled();
});
最后是我的mailer.js
课程:
class Mailer {
constructor() {
this.mailgun = require('mailgun-js')({
apiKey: process.env.MAILGUN_API_KEY,
domain: process.env.MAILGUN_DOMAIN,
});
}
send(to, subject, body) {
return new Promise((reject, resolve) => {
this.mailgun.messages().send({
from: 'Securely App <friendly-robot@securelyapp.com>',
to,
subject: subject,
html: body,
}, (error, body) => {
if (error) {
return reject(error);
}
return resolve('The email was sent successfully!');
});
});
}
}
module.exports = new Mailer();
那么,我如何使用Jest成功模拟和测试这个类?非常感谢您的帮助!
答案 0 :(得分:18)
您不必模拟您的邮件程序类,而是mailgun-js
模块。所以mailgun是一个函数,它返回返回函数messages
的函数send
。所以模拟看起来像这样。
为快乐的道路
const happyPath = () => ({
messages: () => ({
send: (args, callback) => callback()
})
})
表示错误案例
const errorCase = () => ({
messages: () => ({
send: (args, callback) => callback('someError')
})
})
因为你有这2个案例,所以在你的测试中模拟模块是有意义的。首先,您必须使用一个简单的间谍来模拟它,我们稍后可以为我们的案例设置实现,然后我们必须导入模块。
jest.mock('mailgun-js', jest.fn())
import mailgun from 'mailgun-js'
import Mailer from '../../../../server/services/emails/mailer'
由于您的模块使用promises,我们有2个选项可以从测试中返回promise或使用async/await
。我使用后面的更多信息看看here。
test('test the happy path', async() => {
//mock the mailgun so it returns our happy path mock
mailgun.mockImplementation(() => happyPath)
//we need to use async/awit here to let jest recognize the promise
const send = await Mailer.send();
expect(send).toBe('The email was sent successfully!')
});
如果您想测试使用正确的参数调用mailgun send
方法,您需要像这样调整模拟:
const send = jest.fn((args, callback) => callback())
const happyPath = () => ({
messages: () => ({
send: send
})
})
现在您可以检查发送的第一个参数是否正确:
expect(send.mock.calls[0][0]).toMatchSnapshot()
答案 1 :(得分:7)
仅供Google员工和未来访客使用,以下是我为ES6课程设置开玩笑的方法。 我还有一个working example at github,用babel-jest来转换ES模块语法,以便jest可以正确地模拟它们。
<强> __嘲笑__ / MockedClass.js 强>
const stub = {
someMethod: jest.fn(),
someAttribute: true
}
module.exports = () => stub;
您的代码可以使用new调用它,在测试中您可以调用该函数并覆盖任何默认实现。
<强> example.spec.js 强>
const mockedClass = require("path/to/MockedClass")();
const AnotherClass = require("path/to/AnotherClass");
let anotherClass;
jest.mock("path/to/MockedClass");
describe("AnotherClass", () => {
beforeEach(() => {
mockedClass.someMethod.mockImplementation(() => {
return { "foo": "bar" };
});
anotherClass = new AnotherClass();
});
describe("on init", () => {
beforeEach(() => {
anotherClass.init();
});
it("uses a mock", () => {
expect(mockedClass.someMethod.toHaveBeenCalled();
expect(anotherClass.settings)
.toEqual(expect.objectContaining({ "foo": "bar" }));
});
});
});