Consider the following scenario:
Normalizerbehaviour with a
- A User module, with a
changesetfunction that should normalize the
User.changesetfunction calls a default implementation defined such as
normalizer()is defined to return
Application.get_env(:my_app :normalizer, Utils). It means that by default there’s a
normalize_emailfunction in the
Utilsmodule that does the job.
- Note that many other functions in the
Usermodule use the
- In a
mocks.exfile in the
Mox.defmock(NormalizerMock, for: Normalizer)and in
Application.put_env(:my_app :normalizer, NormalizerMock).
Now in our user tests, this is all nice and dandy - we can
expect on the mock and make sure that the correct function is called by all the
User functions such as the
The intent is really just to test that the
User.changeset and other functions delegate the work to the
Utils module - so mocking it gives us a way to verify this. We are not interested in what the
Utils.normalize_email function does from these tests and the only place where the
Utils.normalize_email function is tested is in its own
Utils tests. In other words we just check that the
NormalizerMock.normalize_email function was called exactly once with a parameter we control, and that the result of the
User.changeset function includes this controlled parameter in its return.
However in other tests that target other files and modules, we would like this mock to be absent completely, and have the
User.changeset function normally call onto the
For example, in tests related to a registration controller (or say more integration tests), we call functions on a
Registration module, itself calling the
User.changeset function - and in this case we don’t care to have
User.changeset call a mock - instead it should call its default implementation.
Of course, doing things pixel-perfect would require us to actually mock the
User.changeset function in the
Registration tests, but there is too much overhead here.
Is there a way to have mocks applied only to one test? To one test file? Where would all the moving pieces go (Eg where would the
defmock call be, the
Application.put_env call etc)?
EDIT: Basically a solution we found is to include
stub(NormalizerMock, Utils) in every single other test - which is definitely not acceptable. What we’re trying to understand is how we could do the opposite - have
Utils be the default implementation during all tests, except for a few in which we want to mock and
expect that it’s being called. Does this make sense? Would it for example be OK to have a macro run before each test suite and bake a
setup block for each test calling
stub_with NormalizerMock, Utils so tests that don’t use the mock don’t have it, while tests that use the mock could still perform