Функции модуля Jest mock, используемые в другом модуле

Я новичок в Jest и пытаюсь написать несколько тестов для некоторого существующего кода. Хотя я наткнулся на множество статей Jest и сообщений Stackoverflow о фиктивных функциях в модуле (например, это), я считаю, что пытаюсь реализовать что-то, что либо немного продвинуто, либо очень глупо и требует рефакторинга кода. В любом случае, я не уверен и был бы очень признателен за помощь!

Позвольте мне объяснить мою ситуацию, используя пример кода. Предположим, мы имеем дело с системой электронной коммерции, и в бэкенде есть модуль для получения сведений о заказе из какого-то API:

// get-order-data.js

const getOrderDataFromApi = async (orderId) => {
    // . . . some API call
    console.info("The actual getOrderData function called!");
}

// Added only to emphasize that the entire module shouldn't be mocked
const getOrderDataFromDatabase = async (orderId) => { }

module.exports = {
    getOrderDataFromApi,
    getOrderDataFromDatabase,
}

И еще есть очень похожий модуль для получения данных о доставке заказа:

// get-delivery-data.js

const getDeliveryDataFromApi = async (orderId) => {
    // . . . some API call
    console.info("The actual getDeliveryDataFromApi function called!");
}

// Added only to emphasize that the entire module shouldn't be mocked
const getDeliveryDataFromDatabase = async (orderId) => { }

module.exports = {
    getDeliveryDataFromApi,
    getDeliveryDataFromDatabase,
}

Как вы можете видеть, в каждом модуле есть console.info, который используется для обозначения того, что исходный код был выполнен вместо фиктивного кода.

Теперь предположим, что оба этих модуля используются другой функцией модуля, например:

// combine-order-data.js
const { getDeliveryDataFromApi } = require("./get-delivery-data");
const { getOrderDataFromApi } = require("./get-order-data")

const combineOrderData = async (orderId) => {
    const orderData = await getOrderDataFromApi(orderId);
    const deliveryData = await getDeliveryDataFromApi(orderId);

    return {
        orderData,
        deliveryData,
    };
}

module.exports = {
    combineOrderData,
};

И именно поведение этой функции combineOrderData() я хочу протестировать, смоделировав getOrderDataFromApi() и getDeliveryDataFromApi().

Для этого я создал следующий тестовый файл:

// order.test.js

const { combineOrderData } = require("./combine-order-data");

const mockedOrderData = {
    id: 1,
    amount: 1000,
};

const mockedDelieryData = {
    orderId: 1,
    status: 'DELIVERED',
};

beforeEach(() => {
    jest.mock("./get-order-data", () => {
        getOrderDataFromApi: jest.fn(() => Promise.resolve(mockedOrderData))
    });
    jest.mock("./get-delivery-data", () => {
        getDeliveryDataFromApi: jest.fn(() => Promise.resolve(mockedDelieryData))
    });
});

test("combineOrderData correctly combines data", async () => {
    const combinedOrder = await combineOrderData(111);
});

Когда я сейчас запускаю npx jest, я вижу console.infos в выводе, говорящие мне, что насмешка не удалась:

  console.info
    The actual getOrderData function called!

      at getOrderDataFromApi (get-order-data.js:3:13)

  console.info
    The actual getDeliveryDataFromApi function called!

      at getDeliveryDataFromApi (get-delivery-data.js:3:13)

 PASS  ./order.test.js
  ✓ combineOrderData correctly combines data (28 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.227 s
Ran all test suites related to changed files.

Я думаю, это происходит потому, что когда вызывается combineOrderData(), он создает собственную копию используемых модулей (я думал, что модули Node по умолчанию являются синглтонами; например, существует только одна копия импортированного модуля, которая используется всеми require)?

В любом случае, я не знаю, как правильно этого добиться.

Кроме того, не стесняйтесь комментировать, если структура кода нарушена и рефакторинг решит проблему, но я не вижу, как я могу избежать написания и тестирования кода, который вызывает другие вызовы функций, и поэтому, похоже, я столкнусь с этой проблемой. регулярно.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
82
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел 2 проблемы с тестом

  1. При использовании jest.mock объект должен быть возвращен в обратном вызове, в вашем случае скобки отсутствуют
jest.mock("./get-delivery-data", () => ({
  getDeliveryDataFromApi: jest.fn(() => Promise.resolve(mockedDelieryData)),
}));
  1. Неправильный порядок фиктивного импорта.

Сначала require импортирует настоящие модули вместо фиктивных.

Рабочий тест

jest.mock("./get-order-data", () => ({
  getOrderDataFromApi: jest.fn(() => Promise.resolve(mockedOrderData)),
}));
jest.mock("./get-delivery-data", () => ({
  getDeliveryDataFromApi: jest.fn(() => Promise.resolve(mockedDelieryData)),
}));
const { combineOrderData } = require("./combine-order-data");

const mockedOrderData = {
  id: 1,
  amount: 1000,
};

const mockedDelieryData = {
  orderId: 1,
  status: "DELIVERED",
};

test("combineOrderData correctly combines data", async () => {
  const combinedOrder = await combineOrderData(111);
});

Спасибо за тяжелую работу! Да, заказ импорта был большой ошибкой с моей стороны. Другое дело синтаксис. Функция, переданная jest.mock, по-видимому, должна возвращать объект, поэтому синтаксис жирной стрелки требует () => ({}), а не () => {}. Спасибо еще раз! :-)

ankush981 19.03.2022 07:09

Другие вопросы по теме