Having trouble with mocking functions being called in child processes

Hi there!
If it’s alright, I’m going to explain my problem using screenshots of my code.
I don’t like testing side effects in place where they are being called. I come from Ruby background and I prefer to test for them to be called and then test them separately in their respective modules.
I’m only starting with Elixir, so I’ve done some ground work and found out about Mox.
I’ve got these two modules:

I’ve defined callbacks to form behaviours for them and then in my test.exs config file I’ve configured my app to use mocks instead. Like that:

Then I have another module that is calling previous two modules asynchronously. It’s by design that this third module just has to call their functions asynchronously and never care about them. All the interactions and error handlings are within them:

Then I want to test this third module, that it actually does what it does. I know it seems like a “test for code”, but in this scenario I would prefer that to be as it is. Maybe you can guide me to a better way of structuring my code, I’m a beginner in Elixir :slight_smile: I’ve defined the mocks I needed in test_helper.exs:

and my test file is as follows:

The first expectation (for the delete_message to be called) works out nicely, but strangely for me, the second expectation (for the call/4) is not met. The test fails with expected ShardsOfOcarionWeb.Handlers.MessageHandlerMock.call/4 to be invoked once but it was invoked 0 times

As soon as I change my UpdateHandler module to look like that (pay attention to the handler_received_message function):

tests are now passing.

So I guess there is something with Mox only knowing that mocked function has been called if that mocking function is THE function to start a new process. If it’s being called inside another function on a new process - Mox doesn’t know anything about it. What should I do now? I can theoretically just leave it as is and bear with such a restriction, but I want to know a proper way or at least an explanation on that behaviour. Maybe I’m doing something wrong? I don’t think I can replace Task.start with a GenServer, because I want to avoid creating a single process that handles all the messages for all the users. Thanks in advance!!

You could mark your test as async: false, mox supports global mode:

In my example the solution is to pass the expected function AS callback, that starts a child process. If the expected function is being called in a chain somewhere in the created process - it won’t be caught by Mox and therefor the expect statement won’t suffice. Is it an expected behaviour, or a bug, or me being a noob? :slight_smile:

If I mark my test as async: false and then add setup :set_mox_global to my test it still fails. I guess that’s not an issue.

Testing with Mocks often, eventually slows down your code development. Here’s a way to write smaller focused tests without Mocks. https://www.linkedin.com/pulse/testing-cable-chain-mark-windholtz/

1 Like