Часть 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, связанных с тестом.

Если тест проходит успешно, то либо все ключи предоставлены, либо форма данных совпадает. Это определенно странное чувство, когда не тестируешь каждую существующую клавишу, но ты очень быстро привыкаешь к ней.

На этом завершается эта глава о тестировании типов данных, следующая будет о том, как тестировать асинхронное поведение.

Звонить во внешний мир всегда страшно, но на самом деле это не так. Этого никогда не бывает.