Passing options to Tests

I have used the Mox package to create mocks for some modules during test runs. These are mostly modules that make external HTTP requests. So my test_helper.exs looks now like this (but with multiple mock modules):

ExUnit.start(exclude: [:skip, :external])

Mox.Server.start_link([])

Mox.defmock(HTTPClientMock, for: HTTPClient)

Application.put_env(:my_app, :http_client, HTTPClientMock)

However, I would like to have some tests that actually do make real HTTP requests. Is there a way I can pass an option to bypass the Mox and Application.put_env things so that these special external tests can use the real module instead of the mocks? This is sometimes called “integration tests”. I was hoping that maybe something like this would work:

mix test --no-mocks

But that generates an error:

** (Mix) Could not invoke task "test": 1 error found!
--no-mocks : Unknown option

Maybe what I am trying to do is not a good way. I could write a custom mix task to do the things I want to do in the dev environment, then I would not be fighting against what the test environment wants to do. Does this make sense, what I want to do?

Use tags and explicitly pass in the “real” module in the no-mock tests.

1 Like

will that mean the tests must be run synchronously?

No. Not if written correctly.

test "real request", url: url do
  assert {:ok, _} = M.f(RealHTTP, url)
end

test "mocked request", url: url do
  assert {:ok, _} = M.f(MockedHTTP, url)
end

If though the Appenv is the only possibility to pass in the implementation to use, then you should now redesign the interface.

I am sorry, I do not understand this. What is M.f? To redesign the interface, do you mean that functions must accept the module as an argument?

M.f is the function you want to call, M for “Module” and f for “function”. Commonly used as examples.

Yes, if you want to run them in async mode.

If though the appenv is the only way for you to change the implementation module, then you need to run in sync mode.

1 Like