Spec-Zone.ru › Phoenix

Тестирование контекстов

Исходный код

Требование: Предполагается, что вы ознакомились с вводными руководствами и запустили приложение Phoenix в рабочем состоянии.

Требование: Предполагается, что вы ознакомились с руководством «Введение в тестирование».

Требование: Предполагается, что вы ознакомились с руководствами по контекстам.

В конце руководства «Введение в тестирование» мы сгенерировали HTML-ресурс для публикаций с помощью следующей команды:

$ mix phx.gen.html Blog Post posts title body:text

Это бесплатно предоставило нам несколько модулей, включая контекст Blog и схему Post, а также соответствующие файлы тестов. Как мы узнали из руководства по контекстам, контекст Blog — это просто модуль с функциями для определённой области нашей бизнес-логики, а схема Post соответствует определённой таблице в нашей базе данных.

В этом руководстве мы рассмотрим тесты, сгенерированные для наших контекстов и схем. Прежде чем приступить к работе, запустим mix test, чтобы убедиться, что все наши тесты выполняются без ошибок.

$ mix test
................

Finished in 0.6 seconds
21 tests, 0 failures

Randomized with seed 638414

Отлично. У нас двадцать один тест, и все они проходят!

Тестирование публикаций

Если открыть test/hello/blog_test.exs, вы увидите файл со следующим содержимым:

defmodule Hello.BlogTest do
  use Hello.DataCase

  alias Hello.Blog

  describe "posts" do
    alias Hello.Blog.Post

    import Hello.BlogFixtures

    @invalid_attrs %{body: nil, title: nil}

    test "list_posts/0 returns all posts" do
      post = post_fixture()
      assert Blog.list_posts() == [post]
    end

    ...

В начале файла мы импортируем Hello.DataCase, который, как мы скоро увидим, похож на HelloWeb.ConnCase. Если HelloWeb.ConnCase предоставляет вспомогательные функции для работы с соединениями, что полезно при тестировании контроллеров и представлений, то Hello.DataCase предоставляет функциональность для работы с контекстами и схемами.

Затем мы задаём псевдоним, чтобы обращаться к Hello.Blog просто как к Blog.

Затем мы начинаем блок describe "posts". Блок describe — это возможность ExUnit группировать похожие тесты. Мы сгруппировали все тесты, связанные с публикациями, потому что контексты в Phoenix могут объединять несколько схем. Например, если выполнить эту команду:

$ mix phx.gen.html Blog Comment comments post_id:references:posts body:text

В контексте Hello.Blog появится множество новых функций, а в файле тестов — целый новый блок describe "comments".

Тесты, определённые для нашего контекста, очень просты. Они вызывают функции контекста и проверяют их результаты. Как видите, некоторые из этих тестов даже создают записи в базе данных:

test "create_post/1 with valid data creates a post" do
  valid_attrs = %{body: "some body", title: "some title"}

  assert {:ok, %Post{} = post} = Blog.create_post(valid_attrs)
  assert post.body == "some body"
  assert post.title == "some title"
end

На этом этапе вы можете задаться вопросом: как Phoenix гарантирует, что данные, созданные в одном тесте, не повлияют на другие тесты? Рады, что вы спросили. Чтобы ответить на этот вопрос, поговорим о DataCase.

DataCase

Если открыть test/support/data_case.ex, вы увидите следующее:

defmodule Hello.DataCase do
  use ExUnit.CaseTemplate

  using do
    quote do
      alias Hello.Repo

      import Ecto
      import Ecto.Changeset
      import Ecto.Query
      import Hello.DataCase
    end
  end

  setup tags do
    Hello.DataCase.setup_sandbox(tags)
    :ok
  end

  def setup_sandbox(tags) do
    pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Hello.Repo, shared: not tags[:async])
    on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
  end

  def errors_on(changeset) do
    ...
  end
end

Hello.DataCase — это ещё один ExUnit.CaseTemplate. В блоке using мы видим все псевдонимы и импорты, которые DataCase добавляет в наши тесты. Фрагмент setup для DataCase очень похож на соответствующий фрагмент из ConnCase. Как видим, большая часть блока setup посвящена настройке SQL Sandbox.

Именно SQL Sandbox позволяет нашим тестам записывать данные в базу без влияния на другие тесты. Если вкратце, в начале каждого теста мы открываем транзакцию в базе данных. По завершении теста транзакция автоматически откатывается, фактически удаляя все данные, созданные в тесте.

Кроме того, SQL Sandbox позволяет одновременно запускать несколько тестов, даже если они взаимодействуют с базой данных. Эта возможность доступна для баз данных PostgreSQL и позволяет ускорить тесты контекстов и контроллеров, если добавить флаг async: true при их использовании:

use Hello.DataCase, async: true

При запуске асинхронных тестов с песочницей следует учитывать некоторые особенности. Подробнее см. в Ecto.Adapters.SQL.Sandbox.

Наконец, в конце модуля DataCase находится функция errors_on с примерами её использования. Она нужна для тестирования любых проверок, которые мы захотим добавить в наши схемы. Давайте попробуем добавить собственные проверки и протестировать их.

Тестирование схем

При генерации HTML-ресурса Post Phoenix создал контекст Blog и схему Post. Для контекста был сгенерирован файл тестов, но для схемы — нет. Однако это не значит, что схему не нужно тестировать, — просто до сих пор не было необходимости её тестировать.

Возможно, вы задаётесь вопросом: когда нужно тестировать непосредственно контекст, а когда — схему? Ответ на этот вопрос совпадает с ответом на вопрос, когда добавлять код в контекст, а когда — в схему.

Общее правило: весь код без побочных эффектов следует размещать в схеме. Иными словами, если вы просто работаете со структурами данных, схемами и наборами изменений, помещайте код в схему. В контексте обычно размещают код, который создаёт и обновляет схемы, а затем записывает их в базу данных или отправляет через API.

Мы собираемся добавить дополнительные проверки в модуль схемы — это отличный повод написать тесты для самой схемы. Откройте lib/hello/blog/post.ex и добавьте следующую проверку в def changeset:

def changeset(post, attrs) do
  post
  |> cast(attrs, [:title, :body])
  |> validate_required([:title, :body])
  |> validate_length(:title, min: 2)
end

Новая проверка требует, чтобы заголовок содержал не менее двух символов. Давайте напишем для неё тест. Создайте файл test/hello/blog/post_test.exs со следующим содержимым:

defmodule Hello.Blog.PostTest do
  use Hello.DataCase, async: true
  alias Hello.Blog.Post

  test "title must be at least two characters long" do
    changeset = Post.changeset(%Post{}, %{title: "I"})
    assert %{title: ["should be at least 2 character(s)"]} = errors_on(changeset)
  end
end

Вот и всё. По мере развития нашей бизнес-логики у нас есть чётко определённые места для тестирования контекстов и схем.

← Предыдущая страница Введение в тестирование
Следующая страница → Тестирование контроллеров

Пакет Hex Предпросмотр Hex (текущий файл) Скачать версию ePub

Создано с помощью ExDoc (v0.40.3) для языка программирования Elixir

© 2014 Chris McCord
Licensed under the MIT License.
https://phoenix.hexdocs.pm/testing_contexts.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API