如何使用Jest模拟es6类

der*_*ain 18 javascript unit-testing jestjs

我试图Mailer用jest 模拟一个类,我无法弄清楚如何去做.文档没有提供很多关于它如何工作的例子.过程是我将password-reset触发一个节点事件,当该事件被触发时,我想使用发送电子邮件Mailer.send(to, subject, body).这是我的目录结构:

project_root
-- __test__
---- server
------ services
-------- emails
---------- mailer.test.js
-- server
---- services
------ emails
-------- mailer.js
-------- __mocks__
---------- mailer.js
Run Code Online (Sandbox Code Playgroud)

这是我的模拟文件__mocks__/mailer.js:

const Mailer = jest.genMockFromModule('Mailer');

function send(to, subject, body) {
  return { to, subject, body };
}

module.exports = Mailer;
Run Code Online (Sandbox Code Playgroud)

和我的 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();
});
Run Code Online (Sandbox Code Playgroud)

最后我的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();
Run Code Online (Sandbox Code Playgroud)

那么,我如何使用Jest成功模拟和测试这个类?非常感谢您的帮助!

And*_*rle 19

您不必模拟您的邮件程序类,而是mailgun-js模块.所以mailgun是一个返回函数messages返回函数的函数send.所以模拟看起来像这样.

为了快乐的道路

const happyPath = () => ({
  messages: () => ({
    send: (args, callback) => callback()
  })
})
Run Code Online (Sandbox Code Playgroud)

对于错误情况

const errorCase = () => ({
  messages: () => ({
    send: (args, callback) => callback('someError')
  })
})
Run Code Online (Sandbox Code Playgroud)

因为你有这2个案例,所以在你的测试中模拟模块是有意义的.首先,您必须使用一个简单的间谍来模拟它,我们稍后可以为我们的案例设置实现,然后我们必须导入模块.

jest.mock('mailgun-js', jest.fn())
import mailgun from 'mailgun-js'
import Mailer from '../../../../server/services/emails/mailer'
Run Code Online (Sandbox Code Playgroud)

由于您的模块使用promises,我们有2个选项可以从测试或使用中返回promise async/await.我使用后面的更多信息看看这里.

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!')
});
Run Code Online (Sandbox Code Playgroud)

如果您想测试send使用正确的参数调用mailgun 方法,您需要调整模拟,如下所示:

const send = jest.fn((args, callback) => callback())
const happyPath = () => ({
  messages: () => ({
    send: send
  })
})
Run Code Online (Sandbox Code Playgroud)

现在您可以检查发送的第一个参数是否正确:

expect(send.mock.calls[0][0]).toMatchSnapshot()
Run Code Online (Sandbox Code Playgroud)


Jus*_*ijn 7

仅供Google员工和未来的访问者使用,以下是我为ES6课程设置开玩笑的方法.我在github上也有一个工作示例,使用babel-jest来转换ES模块语法,以便jest可以正确地模拟它们.

__mocks __/MockedClass.js

const stub = {
  someMethod: jest.fn(),
  someAttribute: true
}

module.exports = () => stub;
Run Code Online (Sandbox Code Playgroud)

您的代码可以使用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" }));
    });
  });

});
Run Code Online (Sandbox Code Playgroud)

  • 不适合我.`mockedClass.someMethod`是`undefined`.使用jest 21.2.1. (3认同)
  • @JustusRomijn,你怎么能在箭头函数上调用`new`?当AnotherClass 调用`new mockedClass()` 时,我收到错误“mockedClass 不是构造函数”。 (2认同)