While writing mocks for an Elixir test suite, I found that mock_with sets up a global mock object which prevents you from safely being able to set a test as async: true.
We’ve been using Mox reliably to mock out our own internal code by setting the @callback attribute on methods we wish to mock, thus treating them as behaviours.
The trouble we’ve hit is when we need to mock a third party module, e.g. Redix (a Redis client). We can patch their library with the relevant @callback attributes, but is there a better and cleaner way to implement unobtrusive, async-friendly mocks for third party code?
It’d be awesome to get a community consensus on this!
You could always add your own Redis behaviour and then have Redix simply be one possible implementation of it. IE, mock MyApp.Redis`` instead of mockingRedix`. That’s what I’ve done for stuff at least.
In my opinion, mocking should never ever be done, instead anything that might be mocked should instead be passed into the modules and functions that use it, that way at test time you can pass in something different, this way you retain full async and no surprises about where things come from (plus you might find later that you suddenly need different implementations of something!).
But passing something in at test time, isn’t that what would make it a Mock/Stub?
And passing it it, could happen with several strategies. Could be a parameter on the function, could be set by config, … It depends on the use case what would be the best strategy, but in both cases Mox is a nice helper, in my opinion. It saves some boilerplate code.
We also create our own behaviour mostly MyApp.Redix and then create a wrapper, MyApp.Redix.Wrapper which implement the functions typically as oneliners.