Фабрики тестовых данных
Исходный кодМногие проекты используют внешние библиотеки для создания тестовых данных. Некоторые из этих библиотек называют фабриками, потому что они предоставляют удобные функции для создания различных наборов данных. Однако Ecto умеет управлять сложными деревьями данных, поэтому мы можем реализовать такую функциональность, не полагаясь на сторонние проекты.
Для начала создадим файл "test/support/factory.ex" со следующим содержимым:
defmodule MyApp.Factory do
alias MyApp.Repo
# Factories
def build(:post) do
%MyApp.Post{title: "hello world"}
end
def build(:comment) do
%MyApp.Comment{body: "good post"}
end
def build(:post_with_comments) do
%MyApp.Post{
title: "hello with comments",
comments: [
build(:comment, body: "first"),
build(:comment, body: "second")
]
}
end
def build(:user) do
%MyApp.User{
email: "hello#{System.unique_integer()}",
username: "hello#{System.unique_integer()}"
}
end
# Convenience API
def build(factory_name, attributes) do
factory_name |> build() |> struct!(attributes)
end
def insert!(factory_name, attributes \\ []) do
factory_name |> build(attributes) |> Repo.insert!()
end
end
В нашем модуле фабрик определены четыре «фабрики» в виде разных вариантов функции build: :post, :comment, :post_with_comments и :user. Каждый вариант задаёт структуры с полями, необходимыми базе данных. В некоторых случаях в создаваемой структуре также нужно генерировать уникальные поля, например адрес электронной почты и имя пользователя. Для этого мы вызвали функцию System.unique_integer() из Elixir — если вам нужно строго положительное число, можно вызвать System.unique_integer([:positive]).
В конце мы определили две функции — build/2 и insert!/2. Они упрощают создание структур с заданными атрибутами и вставку данных непосредственно в репозиторий соответственно.
Вот и всё, что нужно для создания наших фабрик. Теперь мы готовы использовать их в тестах. Сначала откройте файл "mix.exs" и убедитесь, что файл "test/support/factory.ex" компилируется:
def project do [..., elixirc_paths: elixirc_paths(Mix.env), ...] end defp elixirc_paths(:test), do: ["lib", "test/support"] defp elixirc_paths(_), do: ["lib"]
Теперь в любом тесте, которому нужно сгенерировать данные, мы можем импортировать модуль MyApp.Factory и использовать его функции:
import MyApp.Factory
build(:post)
#=> %MyApp.Post{id: nil, title: "hello world", ...}
build(:post, title: "custom title")
#=> %MyApp.Post{id: nil, title: "custom title", ...}
insert!(:post, title: "custom title")
#=> %MyApp.Post{id: ..., title: "custom title"}
Создавая нужную нам функциональность на основе возможностей Ecto, мы можем расширять и улучшать наши фабрики любым способом, не ограничиваясь возможностями сторонних библиотек.
© 2014 Chris McCord
Licensed under the MIT License.
https://ecto.hexdocs.pm/test-factories.html