Часть 2 - Карты и структуры
Итак, давайте продолжим наше путешествие по тестированию типов данных Elixir, возможно, с двумя наиболее важными - Maps и Structs.
Хотя Structs - это более строгая форма Maps, поэтому давайте исправим это предложение:
«… Возможно, самый важный тип - Карты» - фанфары и фейерверк.
Код в этих примерах будет намного проще, чем в предыдущих, поскольку мы больше сосредотачиваемся на том, как полностью протестировать карту / структуру, а также как сопоставить шаблон с картой / структурой.
Причина его упрощения заключается в том, что почти все, что выходит за рамки этого пункта в статьях, но также и в Elixir, представлено с использованием этих типов данных.
Итак, мы рассмотрим следующее:
- Тестирование базовой карты с использованием как сравнения равенства, так и сопоставления с образцом
- Тестирование вложенной карты с использованием как сравнения на равенство, так и сопоставления с образцом
- Тестирование структуры с использованием сопоставления с образцом
Как вы можете видеть с помощью Struct, мы не будем использовать сравнение на равенство, причина в том, чтобы воспроизвести, как справляться с аналогичными ситуациями, с которыми мы столкнемся как в Phoenix, так и в Ecto.
Итак, давайте начнем с функции, которая создает очень простую карту:
Очень просто: вызов basic_map
вернет карту с описанием человека, позвонившего Дэйву.
И вот несколько основных способов протестировать эту карту:
Первый тест очень похож на то, что мы видели раньше, базовое утверждение равенства, чтобы убедиться, что объект такой же.
Второй и третий тесты используют сопоставление с образцом, чтобы проверить, соответствует ли карта тому, что мы ожидаем.
Подход, принятый во втором тесте, позволяет нам проверить, существуют ли в совпадении определенные пары ключ-значение, что позволяет нам сопоставить левую часть с правой.
Подход в третьем тесте позволяет нам проверять конкретное значение на карте, которое, если оно истинно, сопоставляет левую и правую стороны вместе.
Это позволяет вам как разработчику предварительно вычислить значение и проверить, соответствует ли оно тому, что вернет фактический вызов функции.
Комбинация этих двух подходов станет очень распространенным явлением, когда мы перейдем к взаимодействию с Ecto / Phoenix.
Итак, следующий этап нашего тура по тестированию карт - это вложенная карта.
Например, если бы у нас было следующее:
У нас будет базовая функция, которая будет возвращать карту с описанием величайшего злодея видеоигр, генерального директора Hyperion Corporation Красавчика Джека и его домашнего питомца Butt Stallion.
Мы можем протестировать эту карту, используя тот же подход, что и раньше:
Единственные незначительные изменения в тестах 2 и 3 по сравнению с basic_map_test.exs
- это то, что мы вкладываем карты в карты.
Тем не менее, и что в этом очень круто, так это то, что даже при глубоком вложении вам все равно не нужно предоставлять пару ключ / значение для каждого аспекта, поскольку Elixir подберет для вас сопоставление с шаблоном.
Сила!!!
Последняя часть нашего путешествия по Maps - это Struct.
Структуры можно рассматривать как более строгие версии Карт, у них есть предопределенные ключи, которые также нельзя добавлять или удалять из них. Они предназначены для описания очень конкретных и статичных фрагментов данных, например, человека, которого мы использовали в первом примере, можно было бы представить как:
Здесь мы объявляем модуль, который будет использоваться для ссылки на Struct, а затем описываем его представление.
Чтобы использовать это, мы можем присвоить ему псевдоним в другом модуле и называть его %Person{}
. Обратите внимание, что это последняя часть имени модуля, а также то, насколько она похожа на синтаксис карты, только с именованным идентификатором для нее.
Незначительное различие между этим %Person{}
и тем, что когда-то использовалось в базовой карте, заключается в добавлении ключей:
- созданный
- обновлено
Это нужно для репликации дополнительных ключей, которые добавляются к структурам, используемым Ecto, это пригодится. Но сначала, как использовать, а затем протестировать структуру:
Вот так просто: назовите его псевдонимом, обратитесь к нему по имени модуля и заполните пустые поля нужными вам значениями.
Важно отметить, что в этом случае любые ключи, которые вы не укажете, будут прибегать к значениям по умолчанию, указанным при построении Struct. Вы можете указать, каким ключам должны быть присвоены значения, используя:
@enforce_keys
выше line 2
в файле Struct вы затем передаете список ключей, которые ДОЛЖНЫ существовать. Отсутствие этих ключей вызовет ошибку, и Struct не будет создан.
Итак, как бы мы это протестировали:
Первый тест очень похож на то, что мы видели раньше: запуск функции, сопоставление с образцом в чем-то конкретном.
Второй намекает на несколько ошибок, которые мы испытаем.
При использовании Ecto / Phoenix мы встретим ключи, которые будут использовать некоторую форму id
или DateTime
. На этом этапе наша стратегия тестирования должна полностью измениться, поскольку мы не сможем воспроизвести или гарантировать, что значения, которые мы передаем для этих ключей, будут такими же.
В общем, ваша стратегия тестирования должна найти другие способы подтвердить ожидаемое поведение, полагаясь на то, что точный идентификатор или временная метка болезненно нестабильны, и вы в будущем будете бесконечно благодарны.
Способ обойти это - не проверять точное равенство, вместо этого сопоставление с образцом в наиболее важных частях Struct, связанных с тестом.
Если тест проходит успешно, то либо все ключи предоставлены, либо форма данных совпадает. Это определенно странное чувство, когда не тестируешь каждую существующую клавишу, но ты очень быстро привыкаешь к ней.
На этом завершается эта глава о тестировании типов данных, следующая будет о том, как тестировать асинхронное поведение.
Звонить во внешний мир всегда страшно, но на самом деле это не так. Этого никогда не бывает.