Рубрики
Без рубрики

Как отделить запросы на тестирование подразделения в узле

EDO Rivai Как насмешлить запрашивать запросы на тестирование подразделения в узле «Старого игрока кассета Philips и ленты, лежа на деревянном полу в Италии» Simone Acquaroli на unsplashlet, скажем, вы решили проверить вашу кодовую базу, и вы прочитали этот блок и интеграционные тесты должны

Автор оригинала: FreeCodeCamp Community Member.

Эдо Ривай

Скажем, у тебя решил проверить вашу кодовую базу и вы прочитали это Устройство и тесты интеграции не должны выполнять ввод/вывод . Вы подумали, что вам нужно издеваться от исходящих HTTP-запросов, что ваше приложение делает, но вы не уверены, где начать.

Я решил спросить Кент C. Додса в Твиттере, как он подходит к HTTP Mocking:

Достаточно честно, Кент! Я думаю, что эта тема стоит более сложная запись.

TL; доктор

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

  1. Разделите HTTP-запросы от вашей бизнес-логики обработки ответа. Очень часто код, который обрабатывает протокол уровня HTTP, не очень интересна, и, возможно, не требует тестирования. Используйте свой инструмент издевательства на выбор, чтобы издеваться от обертки API.
  2. Если вам действительно нужно проверить код HTTP-определения, и ответ от внешнего API является относительно простым, используйте Nock и вручную запрашивать запросы.
  3. Если ответ, который вам нужно тестировать против довольно сложного, используйте Nock-запись Для записи ответа один раз и используйте эту запись для последующих тестов.

Так как сообщество тестирования одержим пирамидами, здесь Ya Go:

Введите Nock

Я бы сказал, что общий консенсус в Nodejs земли – использовать Nock , который работает, исправляя родной узел http . модуль. Это работает очень хорошо, потому что даже если вы не используете http . Модуль напрямую, большинство пользовательских библиотек, таких как Axios. , SuperaGent и Узел-выбор все еще используйте http . под капотом.

Написание и использование Nock Похоже, это выглядит:

// Set up an interceptornock('http://www.example.com')  .post('/login', 'username=pgte&password=123456')  .reply(200, { id: '123ABC' });
// Run your code, which sends out a requestfetchUser('pgte', '123456');

В приведенном выше примере Fetchuser отправит запрос на пост example.com/login Отказ Nock перехватит запрос и немедленно реагирует с предопределенным ответом, не ударяя сеть. Потрясающие!

Это не так просто

Когда я впервые начал с Nock, я с нетерпением начал использовать его с моим модульным тестами. Тем не менее, я быстро получил чувство, что я проводил больше времени, написание ноки, чем на самом деле тестирование бизнес-логики. Одно решение этого – Разделите ваш запрос на свой бизнес-логику . Давайте посмотрим на какой-код.

async function getUser(id) {  const response = await fetch(`/api/users/${id}`);    // User does not exist  if (response.status === 404) return null;
  // Some other error occurred  if (response.status > 400) {    throw new Error(`Unable to fetch user #${id}`);  }    const { firstName, lastName } = await response.json();  return {    firstName,    lastName,    fullName: `${firstName} ${lastName}`  };}

Приведенный выше код отправляет запрос на /API/пользователи/ ID>, и когда найден пользователь, он получает объект содержать ель Стена и ля здание Наконец, он строит объект, который имеет дополнительные Поле Фу LLNAME, который вычисляется из первого и фамилия, полученного по запросу.

Тестовый набор для этой функции может выглядеть так:

it('should properly decorate the fullName', async () => {  nock('http://localhost')    .get('/api/users/123')    .reply(200, { firstName: 'John', lastName: 'Doe });    const user = await getUser(123);  expect(user).toEqual({    firstName: 'John',    lastName: 'Doe,    fullName: 'John Doe'  });});
it('should return null if the user does not exist', async () => {  nock('http://localhost')    .get('/api/users/1337')    .reply(404);    const user = await getUser(1337);  expect(user).toBe(null);});
it('should return null when an error occurs', async () => {  nock('http://localhost')    .get('/api/users/42')    .reply(404);    const userPromise = getUser(42);  expect(userPromise).rejects.toThrow('Unable to fetch user #42');});

Как видите, в этих тестах довольно много происходит. Давайте разделим функцию на две части:

  • код, который отправляет и обрабатывает HTTP-запрос
  • Наша деловая логика

Наш пример немного придумал, так как единственная бизнес-логика, которую у нас есть, – это «вычислить» Funnname Отказ Но вы можете представить, как приложение реального мира будет иметь более сложной бизнес-логики.

// api.jsexport async function getUserFromApi(id) {  const response = await fetch(`/api/users/${id}`);    // User does not exist  if (response.status === 404) return null;
  // Some other error occurred  if (response.status > 400) {    throw new Error(`Unable to fetch user #${id}`);  }
  return response.json();}
// user.jsimport { getUserFromApi } from './api';
async function getUserWithFullName(id) {  const user = await getUserFromApi(id);  if (!user) return user;
  const { firstName, lastName } = user;  return {    firstName,    lastName,    fullName: `${firstName} ${lastName}`  };}

Ради не скучного вас до смерти, я только собираюсь показать вам тесты на нашу деловую логику. Вместо того, чтобы использовать Nock, чтобы издеваться от HTTP-запроса, теперь вы можете использовать свою библиотеку издевательства, чтобы издеваться от нашей собственной обертки API. Я предпочитаю Jest , но этот шаблон не привязан к любой конкретной библиотеке издевательства.

// The function we're testingimport { getUserWithFullName } from './user';
// Only imported for mockingimport { getUserFromApi } from './api';
jest.mock('./api');
it('should properly decorate the fullName', async () => {  getUserFromApi.mockResolvedValueOnce(    { firstName: 'John', lastName: 'Doe }  );    const user = await getUserWithFullName(123);  expect(user).toEqual({    firstName: 'John',    lastName: 'Doe,    fullName: 'John Doe'  });});
it('should return null if the user does not exist', async () => {  getUserFromApi.mockResolvedValueOnce(null);    const user = await getUserWithFullName(1337);  expect(user).toBe(null);});

Как видите, наши тесты выглядят немного очистить. Все HTTP-накладные расходы теперь содержатся в модуле API. То, что мы эффективно сделали, минимизируют поверхность нашего кода, который знает о HTTP-транспорте. И при этом мы минимизируем необходимость использования Nock в наших тестах.

Но логика HTTP именно то, что я хочу проверить!

Я слышу тебя. Иногда подключение к внешнему API является именно то, что вы хотите проверить.

Я уже показал, как вы можете использовать Nock, чтобы издеваться с очень базовым HTTP-запросом. Написание явные ноки для таких простых палей запроса/ответов очень эффективны, и я бы порекомендовал прилипать к нему как можно больше.

Однако иногда содержание запроса или ответа может получить довольно сложный. Писать ручные ноки для таких случаев быстро становится утомительным, а также хрупким!

Очень ясный пример такого случая будет тестировать скребок. Основная ответственность скребка состоит в том, чтобы преобразовать RAW HTML в полезные данные. Однако при тестировании вашего скребка вы не хотите вручную строить HTML-страницу для подачи в Nock. Более того, сайт, который вы намерены царапать, уже есть HTML, который вы хотите обрабатывать, так что давайте воспользуемся этим! Думайте, как снимки, для издевания HTTP.

Скаивание темы из среды

Допустим, я хочу знать все темы, которые доступны на среднем.

Мы будем использовать Scrape-It Чтобы запросить среднюю домашнюю страницу и извлечь тексты из всех элементов, которые соответствуют .ds-nav-item :

import scrapeIt from "scrape-it";
export function getTopics() {  return scrapeIt("https://medium.com", {    topics: {      listItem: ".ds-nav-item"    }  }).then(({ data }) => data.topics);}
// UsagegetTopics().then(console.log);// [ 'Home', 'Tech', 'Culture', 'Entrepreneurship', 'Self', 'Politics', 'Media', 'Design', 'Science', 'Work', 'Popular', 'More' ]

? Хорошо выглядеть!

Теперь, как бы мы пошли за издевание фактического запроса в нашем тесте? Один из способов добиться этого, чтобы пойти на MENIL.com в нашем браузере, View-Source и скопируйте/вставьте, что в Nock вручную. Это утомительно и ошибка. Если мы действительно хотим весь документ HTML, мы можем просто позволить компьютеру обработать это для нас.

Оказывается Nock имеет встроенный механизм называется «запись». Это позволяет вам использовать перехватыватели Nock, чтобы перехватить фактический HTTP-трафик, затем сохранить пару запроса/ответа в файл и использовать это Запись для будущих запросов.

Лично я нашел функциональность записей Nock очень полезных, но эргономика ее может быть улучшена. Так вот мой Бесстыдная пробка для Nock-запись , более эргономичная библиотека для кредитных записей:

Давайте посмотрим, как мы могли бы проверить наш скребок, используя Nock-запись :

import { setupRecorder } from 'nock-record';import { getTopics } from './index';
const record = setupRecorder();
describe('#getTopics', () => {  it('should get all topics', async () => {    // Start recording, specify fixture name    const { completeRecording } = await record('medium-topics');
    // Our actual function under test    const result = await getTopics();        // Complete the recording, allow for Nock to write fixtures    completeRecording();    expect(result).toEqual([      'Home',      'Tech',      'Culture',      'Entrepreneurship',      'Self',      'Politics',      'Media',      'Design',      'Science',      'Work',      'Popular',      'More'    ]);  });});

Первый раз, когда мы запускаем этот тест, он отправит фактический запрос на получение HTML средней домашней страницы:

✓ should get all topics (1163ms)

После этого первого пробега Nock-запись сохранил запись в файл в __nock-Sicketures __/средние темы.json Отказ Для второго пробега Nock-запись автоматически загрузит запись и настроить Nock для вас.

✓ should get all topics (116ms)

Если вы использовали снимки шума раньше, этот рабочий процесс вам будет чувствовать вас очень знакомым.

Теперь мы получили 3 вещи, используя записи:

  1. Detrisinistical: Ваш тест всегда будет работать против того же HTML-документа
  2. Быстро: последующие тесты не будут нажать в сеть
  3. Эргономичный: Нет необходимости вручную вручную

Дайте мне знать, что вы думаете

Подход, который я изложил в этой статье, хорошо работал для меня. Я хотел бы услышать о вашем опыте в комментариях или в Twitter: @Edorivai Отказ

То же самое касается Nock-запись ; вопросы и PR’s Добро пожаловать!

Оригинал: “https://www.freecodecamp.org/news/how-to-mock-requests-for-unit-testing-in-node-bb5d7865814a/”