Правильное тестирование GenServer и Supervisor - PullRequest
0 голосов
/ 03 ноября 2018

Я довольно новичок в реализации Genserver в Elixir. У меня есть случай, когда я пытаюсь управлять каким-то состоянием, и Genserver отлично работает для этого случая. Но я сталкиваюсь с некоторыми сложностями при тестировании Genserver.

У меня есть два теста, которые, кажется, сталкиваются друг с другом. У меня есть тест модульного уровня для моего Genserver и тест более высокого уровня, где функция, которую я вызываю, использует Genserver с модулем. Вот мои два теста:

ПЕРВОЕ:

defmodule MyApp.ScoreTableQueueTest do
  use MyApp.DataCase

  alias MyApp.{ScoreTableQueue}

  setup do
    start_supervised(ScoreTableQueue)
    :ok
  end

  test "pushes value in the queue" do
    assert :ok == ScoreTableQueue.push([1,2,3,4])
  end

  test "pops the full value of the queue" do
    assert [[1,2,3,4]] == ScoreTableQueue.pop()
  end
end

Если я запускаю это изолированно, оно проходит каждый раз. Но если я проведу этот тест, он будет периодически прерываться:

ВТОРОЙ:

  setup do
    start_supervised(ScoreTableQueue)
    :ok
  end

  describe "distribute" do
    test "it distrbutes the correct season points" do
      {:ok, table} = List.first(MyApp.ScoreTableAllocator.distribute())

      assert table.table_details.information == [
               %{team_id: team_3.id, team_score: "N/A"},
               %{team_id: team_2.id, team_score: ps_2.score},
               %{team_id: team_1.id, team_score: ps_1.score}
             ]

      assert table.question_id == question.id
      assert table.season_id == season.id
    end
  end

В моей функции distribute/1 Genserver фактически используется. Если я называю этот тест изолированно, он всегда работает нормально. Но когда я запускаю тесты вместе, кажется, что половина времени прерывается, заставляя меня поверить, что я запускаю один и тот же сервер и передаю информацию на один и тот же сервер между тестами.

Мой вопрос: как мне отделить каждый тест друг от друга? Я хочу, чтобы в каждом тесте был совершенно другой сервер для каждого случая, по крайней мере, для каждого файла. Как Эликсир способ достичь этого?

1 Ответ

0 голосов
/ 03 ноября 2018

В этом случае я бы предложил изменить функции API модуля, чтобы он принимал сервер к использованию, по умолчанию применяя глобальный экземпляр. Что-то вроде этого:

defmodule MyApp.ScoreTableQueue do
  use GenServer

  def push(server \\ __MODULE__, item) do
    GenServer.call(server, {:push, item})
  end

  ...
end

Затем в ваших тестах вы просто запускаете экземпляр для каждого теста:

setup do
  {:ok, pid} = GenServer.start_link(MyApp.ScoreTableQueue, _init_args = nil)
  {:ok, queue: pid}
end

test "pushes value in the queue", %{queue: queue} do
  assert :ok == ScoreTableQueue.push(queue, [1,2,3,4])
end

Когда вы начинаете использовать start_supervised, он запускается в соответствии с функцией child_spec в вашем модуле - я предполагаю, что он задает глобальный экземпляр вашего сервера, поэтому очень возможно, чтобы два теста мешали друг другу.

Другой вариант - установить синхронные тесты (с помощью use MyApp.DataCase, async: false), чтобы они никогда не запускались одновременно. Это может быть еще проще, хотя, возможно, немного медленнее, если ваш набор тестов большой.

...