tubedude

tubedude

HWY Tackle: Deep Req.Test.allow/3 or adding Test-Specific Code in Production Function

Hi everyone,

I’m working on a GenServer module to handle incoming messages in my Elixir application. I’m looking for feedback on how I’m currently handling test-specific code within a production function. Below, I’ve provided the relevant parts of the code for context.

In my test, I create a Req.Test.Stub, but the actual Req.request occurs in a Task that is spawned within the GenServer.

I attempted to bubble up the pid from the Task in the test, but this caused the function execution to occur before the Req.Test.allow could be registered, raising an error that would only happen in the test environment. I also tried using Req.Test.set_req_test_to_shared/1, but I couldn’t get it to work as intended based on the documentation.

As an alternative, I decided to pass the test process pid down to the GenServer and into the Task, where I register Req.Test.allow/3 and add a slight delay to ensure the test runs consistently. This approach is working fine, and I’m happy with it because it avoids introducing extra dependencies. However, I’m unsure if adding test conditionals to the production environment is the right approach.

In other words, how would you tackle this issue?

I’m eager to hear your thoughts.

defmodule MyApp.IncomingTest do
  use ExUnit.Case, async: false

  alias MyApp.Test.Factory

  describe "get_count/0" do
    # To test this scenario, I need both messages to work without causing the process to
    # exit. But since the Stub is not passed to the process, it would break. The Req plug 
    # configuration is passed in the `config/test.exs`.

    @tag :capture_log
    test "two messages" do
      {:ok, incoming_pid} = MyApp.Incoming.start_link([])

      Req.Test.stub(MyApp.Stub, fn conn ->
        Req.Test.json(conn, Factory.create_transcription_response())
      end)

      ptt =
        ~w|test support recorded ptt.json|
        |> MyApp.TestHelpers.read_and_decode_json()

      chat =
        ~w|test support recorded chat.json|
        |> MyApp.TestHelpers.read_and_decode_json()

      MyApp.Incoming.message_received(ptt)
      assert MyApp.Incoming.get_count() == 1

      MyApp.Incoming.message_received(chat)
      assert MyApp.Incoming.get_count() == 2

      :timer.sleep(2000)
      Agent.stop(incoming_pid, :normal)
    end
  end
end
defmodule MyApp.Incoming do
  use GenServer

  # API
  def message_received(params) do
    GenServer.call(__MODULE__, {:message_received, params})
  end

  def handle_call({:message_received, params}, {from, _ref}, state) do
    {:ok, pid} = process_message(params, from)

    new_state =
      state
      |> Map.update(:count, 0, &(&1 + 1))
      |> put_in([:processes, pid], params)

    {:reply, pid, new_state}
  end

  # Private functions
  defp process_message(params, from) do
    {:ok, pid} =
      Task.start(fn ->
        if System.get_env("MIX_ENV") == "test" do
          Req.Test.allow(MyApp.Stub, from, self())
          :timer.sleep(50)
        end

        with {:ok, message} <- cast_message(params),
             {:ok, post_processed_message} <- MyApp.Messages.postprocess_message(message) do
          post_processed_message
        else
          {:error, reason} ->
            Process.exit(self(), reason)
        end
      end)

    Process.monitor(pid)

    {:ok, pid}
  end

Looking forward to your feedback.

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29377 241
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52341 488
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement