Что такое модульное тестирование?
тест - этопроверятьОзначает, работает ли наш код должным образом.
Объектом тестирования может быть любая часть нашей программы. Такой большой, как многоэтапный процесс заказа, такой же маленький, как функция в коде.
Модульное тестирование относится конкретно к тестируемому объекту, находящемуся в программе.наименьшая единицатест. Наименьшей единицей здесь может быть функция, класс и так далее.
Преимущества модульного тестирования
Из-за простоты тестируемого объекта (обычно только один или несколько входов и один выход) это диктует модульное тестирование.Также легко разработать, обычно от нескольких строк до дюжины строк на тест. Простое представление тестового кода, которое можноболее частое выполнение(На самом деле многие фреймворки модульного тестирования имеют режим наблюдения. Модульные тесты автоматически выполняются каждый раз при изменении кода). средства более частого исполненияВыявляйте проблемы раньше.
Только представьте, что по мере того, как код продолжает повторяться, в программе всегда есть определенные места, где часто возникают определенные типы проблем. При отсутствии юнит-тестирования программисты часто говорят «сарафанное радио», и очень вероятно, что та же ошибка будет допущена по неосторожности через некоторое время. С помощью модульного тестирования мы можем написать соответствующий тестовый код для этих проблемных точек и выполнять его каждый раз перед отправкой кода, что может значительно снизить вероятность повторного появления одной и той же ошибки.
Кроме того, чтобы писать модульные тесты для тестируемого объекта, в первую очередь он должен быть легко тестируемым (что выглядит как кусок дерьма). С другой стороны, если вы столкнулись с функцией или классом и вам сложно написать тестовый код, вполне вероятно, что проблема в дизайне вашего кода. Например, он слишком тесно связан с внешними зависимостями. В этом случае процесс написания модульных тестов заставляет нас оптимизировать структуру нашего кода. Разбивайте сложный код на более простые и удобные для тестирования части. Сам процесс такжеСлегка улучшите качество нашего кода.
Ограничения/недостатки модульных тестов
I get paid for code that works, not for tests - Kent Beck
Во-первых, каким бы простым ни был тестовый код, его разработка требует много работы. Это должно занять время разработчика. Поэтому застройщикам необходимо найти оптимальный баланс между инвестициями и доходами.
Во-вторых, покрытие юнит-тестами часто дает разработчикам иллюзию, что юнит-тесты этого кода прошли (тестовое покрытие и 100%) и ошибок быть не должно. На самом деле покрытие юнит-тестами не обязательно связано с качеством кода. Как разработчик, вы должны понимать это на ранней стадии.
Когда писать модульные тесты?
- Во время разработки модульные тесты должны проверять то, что может пойти не так, или те крайние случаи.
- Во время обслуживания модульные тесты должны вращаться вокруг ошибок, и модульные тесты должны быть написаны для каждой ошибки. Это гарантирует, что одна и та же ошибка не появится во второй раз.
Основные понятия модульного тестирования?
Модульное тестирование обычно состоит из следующих частей:
- что тестируется
- какую функциональность объекта тестировать
- Фактический результат
- желаемый результат
- mock/spy (подробнее об этом ниже)
Конкретно для модульного теста он часто включает следующие шаги:
- Этап подготовки: создание параметров, создание шпиона и т. д.
- Фаза выполнения: выполнить тестируемый код с построенными параметрами
- Фаза подтверждения: сравните фактический результат с ожидаемым, чтобы определить, является ли тест нормальным.
- Фаза очистки: устранить влияние фазы подготовки на внешнюю среду, удалить шпиона, созданного на этапе подготовки, и т. д.
Введение в шутку
Jest— это среда тестирования JavaScript, разработанная Facebook. Широко используется внутри Facebook для тестирования различных кодов JavaScript. На его официальном сайте в основном перечислены следующие функции:
- Легко начать
- использовать
create-react-app
илиreact-native init
Созданный проект уже интегрирует Jest по умолчанию. - Существующие проекты, просто создайте файл с именем
__test__
каталог, затем создайте каталог с.spec.js
или.test.js
файл в конце
- использовать
- Мощные встроенные возможности утверждения и имитации
- Встроенная статистика тестового покрытия
- Встроенный механизм моментальных снимков
Хотя официальный сайт Jest много раз представляет React, на самом деле Jest не привязан к React. Вы можете использовать его для тестирования любого проекта JavaScript.
Знакомство с основными функциями Jest
Установить:
npm install --save-dev jest
затем настройтеpackage.json
:
"scripts": {
"test": "jest --color"
}
Затем создайте__tests__
Каталог. jest автоматически перейдет в этот каталог, чтобы найти тестовый код для выполнения.
Далее напишем минимальный тест.
describe('Addition', () => {
it('knows that 2 and 2 make 4', () => {
const val1 = 2;
const val2 = 2;
const result = val1 + val2;
const expectedResult = 4;
expect(result).toBe(expectedResult);
});
});
Давайте посмотрим, как этот модульный тест соответствует элементам и шагам, которые мы упоминали ранее.
элемент:
- Что тестируется:
+
оператор - Какую функциональность объекта тестировать: 2 + 2 = 4
- Фактический результат:
result
- Желаемый результат:
expectedResult
шаг:
- Этап подготовки: линия 3, линия 4
- Стадия исполнения: строка5
- Фаза утверждения: строка 7
- Фаза очистки: нет
Можно увидеть, что при написании модульных тестов нужно следовать «процедурам». На практике мы обычно не создаем столько временных переменных, которые можно сократить как:
describe('Addition', () => {
it('knows that 2 and 2 make 4', () => {
expect(2 + 2).toBe(4);
});
});
toBe
Всего один метод в мощных возможностях утверждений Jest. ты сможешьздесьНайдите подробную документацию по всему спектру поддерживаемых Jest синтаксисов утверждений.
Теперь давайте выполним тестовый код, который мы только что написали:
издевается и шпионит в Jest
Давайте разберемся с mocks и spy на примере.
Предположим, у вас есть следующая функция:
function forEach(items, callback) {
for (let index = 0; index < items.length; index++) {
callback(items[index]);
}
}
Функция очень простая, зациклить первый параметрitems
, и вызовите второй аргумент с каждым элементом в массиве в качестве аргументаcallback
. Как это проверить?
Мы собираемся создать специальную функцию обратного вызова, которая записывает аргументы, передаваемые при каждом вызове, для утверждения.
Вот пример кода:
describe('forEach', () => {
it('should call callback with each item', () => {
const callHistory = [];
const specialCallback = (...args) => callHistory.push(args);
forEach([1, 2], specialCallback);
expect(callHistory.length).toBe(2);
expect(callHistory[0][0]).toBe(1);
expect(callHistory[1][0]).toBe(2);
})
});
здесьspecialCallback
является макетом. Смысл его существования заключается в использовании информации вызываемой для нас статистической функции. Этот паттерн часто используется при модульном тестировании, поэтому в Jest уже есть встроенная поддержка моков. Давайте посмотрим, как использовать:
describe('forEach', () => {
it('should call callback with each item', () => {
const mockFn = jest.fn();
forEach([1, 2], mockFn);
expect(mockFn.mock.calls.length).toBe(2);
expect(mockFn.mock.calls[0][0]).toBe(1);
expect(mockFn.mock.calls[1][0]).toBe(2);
})
});
Это очень удобно, просто нужноjest.fn()
Вы можете получить функцию, захваченную mock-функцией, в один клик. Макет в Jest — это гораздо больше, чем просто подсчет параметров вызова.здесьа такжездесь.
Наконец, давайте поговорим о шпионаже. На самом деле, spy и mock очень похожи, разница лишь в том, что spy используется для мониторинга методов на существующем объекте.
Еще в качестве примера предположим, что у нас есть объекты:
const bot = {
sayHello: (name) => {
console.log(`Hello ${name}!`);
}
}
Мы можем создать и использовать шпиона следующим образом:
describe('bot', () => {
it('should say hello', () => {
const spy = jest.spyOn(bot, 'sayHello');
bot.sayHello('Michael');
expect(spy).toHaveBeenCalledWith('Michael');
spy.mockRestore();
})
});
мы проходимjest.spyOn
создал прослушивательbot
объектsayHello
шпион метода. слушает как шпионbot#sayHello
вызов метода. Поскольку при создании шпиона Jest фактически модифицируетbot
объектsayHello
свойство, поэтому после завершения утверждения мы также передаемmockRestore
чтобы восстановитьbot
объект оригиналsayHello
метод.
здесьБолее подробное введение в Jest#spyOn можно найти здесь.
В действии: написание полного модульного теста с использованием Jest
До сих пор были введены рутина модульного тестирования и базовое использование Jest. Давайте завершим сегодняшнее обсуждение полным примером.
Проверяемая функция называетсяgetImageDomain
. Основная функция заключается в выборе доменного имени сервера изображений для skuId. Если skuId не передан, будет возвращено случайное доменное имя:
const domains = [
'img10.360buyimg.com',
'img11.360buyimg.com',
'img12.360buyimg.com',
'img13.360buyimg.com',
'img14.360buyimg.com',
];
const getImageDomain = (skuId) => {
if (skuId) {
return domains[skuId % 5];
} else {
return domains[Math.floor(Math.random() * 5)];
}
}
Соответствующий тестовый код выглядит следующим образом, поскольку логика относительно проста, подробно разбирать ее не будем:
describe('getImageDomain', () => {
it('should select domain based on skuId if provided', () => {
expect(getImageDomain(1)).toBe('img11.360buyimg.com');
});
it('should select a random domain based on Math.random if skuId not available', () => {
const spy = jest.spyOn(Math, 'random').mockImplementation(() => 0.9);
expect(getImageDomain()).toBe('img14.360buyimg.com');
expect(spy).toHaveBeenCalled();
spy.mockRestore();
});
});
напиши в конце
Тестирование — это средство, а не цель.
Качество программного обеспечения не проверяется, а проектируется и поддерживается.