BitGonzo
Sensible way to abstract away request client library in my application?
I’ve started to test my application and immediately run into the mock debate. Just done reading:
The above suggests using explicit contracts and config variables to manage environment-specific dependencies initially, and then goes on to suggest the simpler method of injecting dependency directly.
However, my current method is a little different. I am using explicit contracts and delegation such as:
config :myapp, request_client: MyApp.Tesla.Request
defmodule MyApp.Request do
@client Application.get_env(:myapp, :request_client)
defdelegate make, to: @client
@callback make(etc) :: etc
end
defmodule MyApp.Tesla.Request do
@behaviour MyApp.Request
use Tesla
plug Tesla.Middleware.Retry, delay: 1000, max_retries:: 3
def make do
# perform request, return response
end
end
This gives me a common interface and call MyApp.Request.make, while also giving me the ability to switch out the client with configuration, which I will use during testing.
Does this look sensible? Is there something inherently wrong with the above approach or, in your opinion, an improvement?
The second question is about testing MyApp.Tesla.Request – perhaps I can switch out the client I use in testing, but surely I still need to test that my Tesla request is configured/running properly.
Most Liked
BitGonzo
Awesome! I’m on Vim. I imagine there is a plugin, or could write a simple one. At the minute I’m just running dialyzer as part of my build process.
hubertlepicki
Maybe examples here will make it a bit more clear: http://slides.com/hubertlepicki/mox
NobbZ
So dialyzer is totally right.
Tesla.get/* and Tesla.post/* all are returning Tesla.Env.t according to their @spec. A Tesla.Env.t will never match a {:ok, _} as it is a struct, not a tuple.
If though Tesla.get/* does return a tuple instead, you need to file a bugreport at tesla to fix their specs (or implementation).
BitGonzo
I don’t understand. That code works – the result of Tesla.get is a tuple with {:ok, response} or {:error, struct (with reason)}?
In that case - if this is a bug in their spec/impl, apart from telling Tesla about it, what would be the proper way to handle this? Patch the spec myself? Wait for it to be fixed? Tell dialyzer to ignore?
NobbZ
Its easiy.
You are using Tesla.get/1, which is @speced to return Tesla.Env.t, but implemented to return {:ok, any()} | {:error, any()} (or something similar).
You are running dialyzer in the context of your application, so dialyzer will trust in the specs of external libraries without validating them.
If you were running dialyzer in the context of Tesla it will probably complain that the functions do not fullfill their contract (do not remember the exact message).








