alexocode/knigge

Must set `check_if_exists?` to false when using Mox

Closed this issue · 7 comments

Just a heads up. In order to get my project to compile when using this library in combination with Mox, I had to set check_if_exists? option to false.

I have my mock defined in /test/support/mocks.ex which is included in my elixirc_paths, as recommended in the Mox documentation to provide compile-time support, but the project wouldn't compile when I use Knigge unless I set that option.

That option isn't documented in the Knigge.Options docs and I only found out about it looking at the tests you wrote for issue #2.

I came across that too. The option is deliberately not documented because it's meant for internal use but I've realized that this is always going to be an issue in tests.

We're considering to make the check configurable per mix environment and default to exclude: :test.

This way it's ensured at compile time that the implementation exists for dev and prod while providing necessary flexibility for test (where a misconfiguration would result in failing tests anyway).

What do you think?

That sounds like it could work pretty well 👍

Cool library by the way. I hadn't seen the pattern of configuring the implementation in the behaviour module and delegating calls to the implementation but I really like it. It's going to make a bunch of my code a lot cleaner.

Fixed in release 1.0.3.

A heads up for you: check_if_exists? has been replaced with check_if_exists as discussed above. So you'll have to update your code and check_if_exists? when you upgrade. 🙂

Still seeing compilation errors under test with 1.0.3

mix.lock

  "knigge": {:hex, :knigge, "1.0.3", "5a1d3b42db6ef2e902b77cf5029c077dbc44dc88fddc20955560497867419670", [:mix], [], "hexpm"},

Behaviour

defmodule Ryath.Auth0Client do
  use Knigge, otp_app: :ryath

  @type client_id() :: String.t()
  @type client_secret() :: String.t()
  @type audience() :: String.t()

  @callback get_token(client_id(), client_secret(), audience()) ::
              {:ok, map()} | {:error, :token_error}
end

mocks.ex

Mox.defmock(Ryath.Auth0Client.Mock, for: Ryath.Auth0Client)
mix test
Compiling 26 files (.ex)

== Compilation error in file lib/ryath/auth0_client.ex ==
** (CompileError) lib/ryath/auth0_client.ex:2: the given module could not be found: Ryath.Auth0Client.Mock
    lib/knigge/error.ex:21: Knigge.Error.raise_compile_error/2
    lib/knigge/module.ex:8: Knigge.Module.ensure_exists!/3
    lib/ryath/auth0_client.ex:2: (module)
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6

Well TIL: Mix.env/0 always returns :prod for dependencies.

I've written tests for this but obviously in the scope of Knigge. I'm sorry for that, I'll see if I can find out how to access the callers Mix.env/0.

For now you can work around this by calling use Knigge, check_if_exists: Mix.env() != :test.

I managed to find a solution but this results in compiler warnings that the module is not defined which can not be disabled yet. Seems like Elixir 1.10 offers per module options to mute this warning.

I've published 1.0.4 which now definitely works, I've verified it in a test project.

In addition I've added #4 because the current solution still generates compiler warnings which are not easily suppressed. For this I've also added a section to the docs and README.

Thank you for your patience @sbennett33 and thanks for using Knigge at this early stage. 🙂