Шутный юнит-тест для шпионажа по методу более низкого уровня (NodeJS) - PullRequest
0 голосов
/ 29 января 2019

Попытка шпионить и переопределить функцию на два уровня ниже, используя Jest.

Результаты теста говорят: «Ожидается, что фиктивная функция была вызвана, но она не была вызвана».

// mail/index.unit.test.js
import mail from './index';
import * as sib from '../sendinblue';

describe('EMAIL Util', () =>
  test('should call sibSubmit in server/utils/sendinblue/index.js', async() => {
    const sibMock = jest.spyOn(sib, 'sibSubmit');
    sibMock.mockImplementation(() => 'Calling sibSubmit()');
    const testMessage = {
      sender: [{ email: 'foo@example.com', name: 'Something' }],
      to: [{ email: 'foo@example.com', name: 'Something' }],
      subject: 'My Subject',
      htmlContent: 'This is test content'
    };
    await mail.send(testMessage);
    expect(sibMock).toHaveBeenCalled();
  })
);

mail.send () приходит отсюда ...

// mail/index.js
import { sibSendTransactionalEmail } from '../sendinblue';

export default {
  send: async message => {
    try {
      return await sibSendTransactionalEmail(message);
    } catch(err) {
      console.error(err);
    }
  }
};

Который использует API SendInBlue через axios (почему мне нужно издеваться) ...

// sendinblue/index.js
import axios from 'axios';
import config from '../../config/environment';

export async function sibSubmit(method, url, data) {
  let instance = axios.create({
    baseURL: 'https://api.sendinblue.com',
    headers: { 'api-key': config.mail.apiKey }
  });
  try {
    const response = await instance({
      method,
      url,
      data
    });
    return response;
  } catch(err) {
    console.error('Error communicating with SendInBlue', instance, err);
  }
}

export const sibSendTransactionalEmail = message => sibSubmit('POST', '/v3/smtp/email', message);

Я принял почту.send () вызовет sibSendTransactionalEmail () в другом модуле и вызовет sibSubmit (), фокус jest.spyOn ().Интересно, где я ошибся.

1 Ответ

0 голосов
/ 29 января 2019

jest.spyOn заменяет метод на объекте, которому он передается, шпионом .

В этом случае вы передаете sib, который представляет ES6модуль экспортирует из sendinblue.js, поэтому Jest заменит модуль экспорта для sibSubmit шпионом и даст шпиону ложную реализацию, которую вы предоставили.

mail.send, затем вызоветsibSendTransactionalEmail , который затем вызывает sibSubmit напрямую .

Другими словами, ваш шпион не вызывается, потому что sibSendTransactionalEmail не вызывает модуля экспорта для sibSubmit, он просто вызывает sibSubmit напрямую.

Простой способ решить эту проблему - заметить, что "Модули ES6 поддерживают циклические зависимости автоматически" , поэтому вы можете просто импортировать модуль ви вызовите sibSubmit из sibSendTransactionalEmail, используя экспорт модуля:

import axios from 'axios';
import config from '../../config/environment';
import * as sib from './';  // import module into itself

export async function sibSubmit(method, url, data) {
  let instance = axios.create({
    baseURL: 'https://api.sendinblue.com',
    headers: { 'api-key': config.mail.apiKey }
  });
  try {
    const response = await instance({
      method,
      url,
      data
    });
    return response;
  } catch(err) {
    console.error('Error communicating with SendInBlue', instance, err);
  }
}

export const sibSendTransactionalEmail = message => sib.sibSubmit('POST', '/v3/smtp/email', message);  // call sibSubmit using the module export

Обратите внимание, что замена экспорта модуля ES6 на jest.spyOn, как этот , работает, потому что Jest переносит модули ES6 вNode модулей таким образом, что позволяет их мутировать

...