Summary
Это функция, которая создаёт объект определённого типа с уже установленными валидными значениями по-умолчанию. И предоставляет возможность вручную определить необходимые для работы параметры на выбор.
Введение
Хочу рассказать про штуку, которую считаю одной из полезнейших, что я внедрил в проекты Ozon Эквайринга за последний год. Это небольшой, но очень важный шаг к приложению, которое можно просто и быстро протестировать
Проблема
Когда разработчик пишет юнит тест, часто получается так, что входной параметр тестируемой функции это объект, у которого есть данные, которые обязательно должны быть определены. Даже если они не нужны для конкретного теста.
Приходится каждый раз определять начальные значения для каждого юнита. Выглядит это примерно так:
- В следующем тесте на изменение имени, телефона и т.п. придётся создать такой же объект, где нужно подставить только одну строку;
- Если объект сложный и состоит из множества объектов, то воспроизвести нужно и их.
Решение
Решением этой проблемы могут быть фабрики значений по-умолчанию. Для того, чтобы начать их использовать, нужно добавить в файл к типу функцию с таким же именем, просто в camelCase:
Всем полям присваиваются значения по умолчанию. Через параметр функции передаётся переменная data: Partial<User>
с переопределением некоторых полей, которые пользователь кода захочет изменить.
Если нужно будет добавить новое поле в тип, то с фабрикой это легко сделать, не сломав ничего в множестве тестов, где он используется. Линтер сразу же начнёт ругаться: “Добавь в фабрику дефолтное поле”.
Результат
- Код теста упрощается
- Уменьшается количество визуального мусора
- При добавлении новых полей в класс, не ломаются уже написанные тесты
Типы и их дефолтные значения
string
-""
number
-0
boolean
-false
Array<any>
-[]
Object какого-то типа
-фабрика этого типа
Любое опциональное значение
-undefined
Некоторые мысли
- На один тип лучше делать один файл;
- Тип и фабрика должны лежать в одном файле, так их легче поддерживать;
- Фабрику лучше называть так же, как сам тип, просто с маленькой буквы. Это позволяет быстро находить нужную фабрику и не допускает конфликта имён;
- Фабрики типа можно использовать для дефолтного стейта в сторе Redux, Vuex;
- Если есть желание использовать фабрики повсюду в проекте, то лучше этого избегать, и стараться формировать тип так, чтобы он содержал в себе только то, что будет действительно использоваться. У моего друга Android-разработчика в проекте вообще стоит декоратор
@testOnly
над фабриками дефолтных значений.
Тэги
Вдохновляют
- @shevtsov200
- Супрематисты, но эти не то чтобы сильно
Материалы
- Владимир Хориков: Принципы юнит тестирования - В разделе 3.3.3 он использует похожие фабрики
- James Shore: Testing Without Mocks: A Pattern Language - Джеймс Шор называет это Parameterless Instantiation и добавляет туда уже ненулевые значения, но суть та же