Fl4m3Ph03n1x
Background
I have a small app where I have a pool that creates several workers. The pool acts as a supervisor for said workers.
Both (the pool and the workers) have a dependency on another module, the ExRegistry. This module registers any process that provides a key.
Test
While using Mox I want to make sure the worker is doing its job correctly, I don’t really want to test the registry just yet. So I stub the RegistryMock with the real one:
stub(RegistryMock, :via_tuple, &ExRegistry.via_tuple/1)
{:ok, _pid} = Worker.start_link({1})
Problem
The problem here is that the pool fails to start:
Could not start application mox_issue: MoxIssue.Application.start(:normal, []) returned an error: shutdown: failed to start child: MoxIssue.Pool
** (EXIT) an exception was raised:
** (Mox.UnexpectedCallError) no expectation defined for MoxIssue.RegistryMock.via_tuple/1 in process #PID<0.163.0>
I think this happens because the pool is another process, which also needs access to the RegistryMock but Mox fails to give it access. To test this I set the options on Mox for global so all processes can use the mocks, but it still fails with the same error.
Question
How does Mox behave with multiple processes requiring the same Mock?
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










First 10 of 11 Posts
peerreynders
A quick scan of the source code suggests to me that expectations are registered by process id - if that is true the same expectation would have to registered by/for the pool process.
Fl4m3Ph03n1x
So, how would I make this test pass? It would be impossible unless I override the
global_owner_pidand that’s impossible/not a good idea.Perhaps my approach to testing this concept is wrong? How would you do it?
jeremyjh
Mox supports a global mode.
peerreynders
This approach seems to work (when
setup :set_mox_globaldoesn’t):Mox.allow/3The only way I could get global mode to work:
The way I understand the documentation this should only work in global mode …
and yet the task process has no problem using the mocked functions.
al2o3cr
There’s a note about this below the example - on Elixir 1.8+ Mox can use
$callersto detect when a parent process has an expectation set. (see also the similar machinery inDBConnection)That’s not going to help for your case, though, since the test process and the registry aren’t related in a parent->child sense.
peerreynders
It seems in global mode the expectations have to come from a single process:
Managing multiple sets of mocks with explicit allowances is a bit more work:
Getting
setup :set_mox_globalto work:Seems what is happening is that
setup :set_mox_globalmakes the individual test the global owner for the duration of the test - consequently that testing process would have to register all the expectations that are to be shared for the scope of that particular test.Fl4m3Ph03n1x
Been there, done that
@peerreynders That’s quite a lot to go through, I am still digesting it!
Fl4m3Ph03n1x
@peerreynders After reading all of your replies, I do feel like it’s totally overkill to define a GenServer module for each function of the interface I want to test.
Surely, @josevalim had a better idea in mind when he created Mox, I am fairly certain this is not the way Mox should be used and that I am missing something here.
Your replies have been invaluable though, I have learned a lot!
I will however look into other solutions for this issue and if I fail, I guess I will simply ditch Mox, as I don’t think the library is worth all the extra complexity I am paying - unless I am the only one here who thinks that creating a GenServer for each function of each interface is overkill, in which case I will just politely disagree
hubertlepicki
I don’t know if you should be using it like that in first place. You are attempting to mock the piece of infrastructure you are in control, and mocking/stubbing in my mind should be reserved to dealing with elements of infrastructure you don’t have control over: like remote services/endpoints, systems talking to external systems etc.
If you don’t want to touch ExRegistry in your tests, you could write a testing module that does something similar that makes sense in your test and inject it in it’s place for testing purposes, or isolate the worker further and test it in isolation.
peerreynders
My sense is that a typical use case is something like:
where
AdderandMultiplierare pieces of the SUT - setting up just enough environment to support the test.I don’t think it was meant to be used with a whole and running SUT.