Моки и стабы

В процессе тестирования приложений на фреймворке Solid.js часто возникает необходимость изолировать различные компоненты и функции для упрощения тестов и повышения их скорости. Один из способов достижения этой изоляции — использование моков и стабов. Эти два подхода широко применяются в юнит-тестах для имитации поведения зависимостей компонентов, что позволяет сосредоточиться только на тестируемом элементе.

Моки

Моки (Mocks) — это объекты, которые заменяют реальные зависимости в тестах. Они позволяют задавать ожидаемое поведение объектов и проверять, были ли вызваны определённые методы или функции с нужными аргументами. Моки широко используются для имитации работы с внешними API, сервисами или хранилищами данных. В Solid.js они могут быть полезны для замены сторонних библиотек или сервисов, таких как API, сторонние компоненты, или функции работы с состоянием.

Пример использования моков в Solid.js:

Допустим, у нас есть компонент, который использует API для получения данных:

import { createSignal, onCleanup } from "solid-js";

function MyComponent() {
  const [data, setData] = createSignal(null);

  const fetchData = async () => {
    const response = await fetch("https://api.example.com/data");
    const result = await response.json();
    setData(result);
  };

  onCleanup(() => {
    // Очистка
  });

  return (
    <div>
      {data() ? <p>{data().name}</p> : <p>Loading...</p>}
    </div>
  );
}

Чтобы протестировать этот компонент, можно использовать мок для fetch. В тестах мы можем подменить оригинальный метод fetch на мок-версию, которая будет возвращать заранее подготовленные данные, не выполняя настоящего HTTP-запроса:

import { render } from "@testing-library/solid";
import MyComponent from "./MyComponent";

// Мокируем fetch
global.fetch = jest.fn(() =>
  Promise.resolve({
    json: () => Promise.resolve({ name: "Mocked Data" })
  })
);

test("renders fetched data", async () => {
  const { getByText } = render(MyComponent);
  
  // Проверка, что компонент отрендерил данные
  expect(getByText("Mocked Data")).toBeInTheDocument();
});

Здесь мы заменили fetch на мок-версию, которая всегда возвращает объект с нужной структурой. Такой подход позволяет тестировать логику компонента без необходимости обращаться к реальному API.

Стабы

Стабы (Stubs) — это также подставные объекты, которые используются для имитации поведения зависимостей. В отличие от моков, стабы не отслеживают вызовы методов и не проверяют, как именно использовалась зависимость. Вместо этого они просто предоставляют предсказуемое поведение. Стабы полезны в тех случаях, когда нужно не проверять взаимодействие с объектами, а лишь изолировать тестируемую часть приложения от сторонних воздействий.

В Solid.js стабы могут быть полезны для изоляции компонента от внешнего состояния или сервисов. Например, можно использовать стаб для замены сложной логики работы с локальным хранилищем или глобальным состоянием.

Пример использования стабов в Solid.js:

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

import { createSignal } from "solid-js";

function Counter() {
  const [count, setCount] = createSignal(0);

  const increment = () => setCount(count() + 1);
  
  return (
    <div>
      <p>{count()}</p>
      <button onCl ick={increment}>Increment</button>
    </div>
  );
}

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

import { render } from "@testing-library/solid";
import Counter from "./Counter";

// Стаб для createSignal
const createSignalStub = (initialValue) => {
  let value = initialValue;
  return [
    () => value,
    (newValue) => { value = newValue; }
  ];
};

test("renders and increments counter", async () => {
  // Используем стаб вместо оригинальной реализации createSignal
  const [count, setCount] = createSignalStub(0);
  
  const { getByText } = render(Counter);
  
  expect(getByText("0")).toBeInTheDocument();
  
  // Имитируем нажатие на кнопку
  setCount(count() + 1);
  
  expect(getByText("1")).toBeInTheDocument();
});

Здесь мы подставили стаб для createSignal, который позволяет вручную управлять значением сигнала. Такой подход позволяет тестировать логику компонента, не завися от реальной реализации состояния в Solid.js.

Моки vs Стабы

Хотя моки и стабы выполняют схожие задачи, они имеют несколько ключевых различий:

  • Моки отслеживают вызовы методов и могут проверять, как именно объект используется в процессе теста. Они идеально подходят для проверки взаимодействия с зависимостями и убеждения, что компонент правильно вызывает внешние функции.
  • Стабы предоставляют фиксированное поведение, не отслеживая вызовы и не проверяя взаимодействие. Они полезны для замены сложных зависимостей на простые подставные объекты, когда важно только изолировать тестируемую часть.

В контексте Solid.js оба подхода могут быть полезны, в зависимости от цели теста. Моки могут использоваться для проверки вызова методов, взаимодействующих с внешними сервисами, в то время как стабы — для изоляции компонентов от сложных состояний или библиотек.

Заключение

Правильное использование моков и стабов позволяет сделать тесты более изолированными, быстрыми и предсказуемыми. Моки предоставляют гибкость для проверки взаимодействий между компонентами и их зависимостями, в то время как стабы упрощают процесс тестирования, заменяя сложные или ненужные зависимости предсказуемыми значениями. В Solid.js эти подходы легко интегрируются в тестовую среду, позволяя тестировать компоненты с минимальными внешними зависимостями.