В настоящее время я пишу небольшую игру с Elixir и Phoenix, и у меня возникла проблема с написанием тестов для контроля производительности моей игры.
По сути, у меня есть GenServer, который зацикливается бесконечно, посылая Само бросает, который действует как основной l oop игры, обрабатывая большую часть логи c. Давайте назовем это "gamel oop". На каждой итерации gamel oop отправляет сообщение (через MyAppWeb.Endpoint.broadcast
на канал, содержащий обновленное состояние игры. Канал получает это сообщение через handle_in
и перенаправляет новое состояние игры всем подключенным клиентам. Канал также отправляет сообщение. сообщение, содержащее время, когда обновление состояния было получено на другой GenServer, который отслеживает различные метрики.
Это прекрасно работает в разработке и производстве, но не в тестах. Когда в тестовой среде канал не работает Кажется, я не получаю трансляции от gamel oop. Я могу подключиться к сокету, присоединиться к каналу и получить сообщения pu sh из него из тестового примера (спасибо ChannelCase
), но что я делаю больше похож на интеграционный тест, поэтому отправка сообщений на канал из тестового примера не имеет смысла.
Это нормальное поведение? Если да, то есть ли способ изменить мою игру или архитектуру моего теста, которая будет работать лучше? Если нет, то какой шаг я пропускаю? Я смотрел в Интернете, но не мог найти ничего об этом. Я также пытался поиграть с конфигурацией тестовой среды (в частности, включив опцию server
в конфигурации Endpoint), но не смог заставить ее работать.
Вот немного кода, чтобы лучше проиллюстрируйте, что я делаю.
Gamel oop GenServer:
defmodule MyApp.Gameloop do
use GenServer
alias MyAppWeb.Endpoint
# Client
def start_link([]) do
GenServer.start(__MODULE__, [], name: __MODULE__)
end
# Server (callbacks)
@impl true
def init([]), do: {:ok, %{}}
@impl true
def handle_info(:loop, state) do
updated_state = handle_game_logic(state)
Endpoint.broadcast!("game_state", "new_state", updated_state)
Process.send_after(self(), :loop, calculate_time_to_wait_based_on_tick_rate())
{:noreply, updated_state}
end
end
Сокет:
defmodule MyAppWeb.SpectateSocket do
use Phoenix.Socket
## Channels
channel "game_state", MyAppWeb.GameStateChannel
def connect(_params, socket), do: {:ok, socket}
def id(_socket), do: nil
end
Канал:
defmodule MyAppWeb.GameStateChannel do
alias MyApp.Monitor
alias :erlang, as: Erlang
use MyAppWeb, :channel
def join("game_state", _payload, socket) do
{:ok, socket}
end
def handle_in("new_state", payload, socket) do
broadcast(socket, "new_state", payload)
Monitor.store_broadcast_time(Erlang.monotonic_time())
{:noreply, socket}
end
end
Опять же, это прекрасно работает в dev / prod, но handle_in
канала никогда не вызывается в тестах.
Спасибо за любую помощь!