How to test supervised, named, Agents?

877 views
Skip to first unread message

Doug Goldie

unread,
Sep 2, 2014, 8:00:40 PM9/2/14
to elixir-l...@googlegroups.com
What is the best practice to run isolated tests with a supervised, named Agent?

I have an Agent with 4 tests.
The tests worked fine starting the Agent in a setup block (like elixirsips #78)


setup
do
 
{:ok, agent} = ConsumerAgent.start_link
end



But after putting it in a supervisor tree and globally naming it, I get errors like this.

 
   
** (MatchError) no match of right hand side value: {:error, {:already_started, #PID<0.167.0>}}


So, I guess ExUnit is creating my global Agent by running the application supervision tree.

Removing the setup block gets rid of the error.
But now some tests break -- usually the last one -- because state is being carried over from test to test by the Agent.

For this particular agent, I could merge the tests into one... not a great practice.
I suppose I could write a reset function that initializes the Agent dict....

but what's the right way here to run isolated tests?

thanks,

-doug.




Saša Jurić

unread,
Sep 3, 2014, 2:07:23 AM9/3/14
to elixir-l...@googlegroups.com
One option is to run 
mix test --no-start 
which will prevent the application from being started.

José Valim

unread,
Sep 3, 2014, 7:13:13 AM9/3/14
to elixir-l...@googlegroups.com
I would typically allow the name to be given as argument. In ConsumerAgent:

    @name __MODULE__

    def start_link(opts \\ []) do
      opts = Keyword.put_new(opts, :name, @name)
      Agent.start_link(opts)
    end

    def call_the_agent(name \\ @name) do
      Agent.get(@name, ...)
    end

Then you can use the direct API in your code but pass the agent explicitly during tests.



José Valim
Skype: jv.ptec
Founder and Lead Developer


--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Doug Goldie

unread,
Sep 4, 2014, 3:39:24 PM9/4/14
to elixir-l...@googlegroups.com, jose....@plataformatec.com.br
Thanks Sasa, Jose,

Both solutions work! 
More importantly, both pushed me to learn more Elixir!
Here's a few comments / questions....

1) Using mix test --no-start
Cool, I didn't realize that was there.

When I tried this, I got an error for the Logger application not running.
Fixed that with Application.start(:logger).
It seemed to make sense to move it to the test_helper.exs, which works.
But it doesn't look like you can move the start option to the test helper because its used earlier in the app.start.

It feels like it might be inflexible as your app mature because
I think you'd be committed to using --no-start all the time.

Would it make sense to have something for default Mix cli options? like a '.mix' file.
I'm not sure it's needed...just thinking out loud :-)

Again this works great. 

2) Passing agent name in args.
I was happy how close my Agent was to Jose's example :-)
I went with this approach. It does make the tests a little more wordy, but not bad.
I noticed I didn't have to use on_exit.

So, the Agent is stopped when the test process dies?

thanks again !



  setup
do
   
{:ok, agent} = ConsumerAgent.start_link name: {:global, __MODULE__ }
    {:ok, agent: agent}
 
end

  test
"get current consumer key", context do
   
assert ConsumerAgent.get(context[:agent]) == 0
 
end
...
 

José Valim

unread,
Sep 4, 2014, 3:42:31 PM9/4/14
to elixir-l...@googlegroups.com
So, the Agent is stopped when the test process dies?

Yes! The test process exits with reason :shutdown, which causes all linked processes to quietly shutdown too!
Reply all
Reply to author
Forward
0 new messages