I’ve been having a hard time testing Contexts and/or external service clients.
For the simplicity I want to provide a small example and ask for advice on how to test this.
File structure:
|- app
|---- listings
|------- car.ex
|------- listings.ex
|---- car_service
|------- http_client.ex
|------- test_client.ex
|------- car_service.ex
Lets say I’m using a public function on the Listings
context called info
.
def info(%Car{} = car) do
case CarService.fetch_info(car) do
{:ok, _} ->
# handle success logic
:ok
{:error, _} ->
# handle failure logic
:error
end
end
As you can see this is actually calling an external service to fetch information about a car.
In order to test the CarService
most people use environment based configuration for dependency injection
defmodule CarService do
# http_client on dev
# test_client on test
@client Application.get_env(:app, :car_service)[:client]
def fetch_info(car_data, client \\ @client) do
client.get("route", car_data)
end
end
and then pattern match on certain parameters in their test_client
to get their expected results in tests.
This feels like a pain point to me since now I’d have to pattern match on specific key/values in car_data
which would be creating additional implementation details in order to test boundaries (simulating all potential results from service).
Maybe I’m going about this the wrong way but I’d want a client per type of response, each implementing a client behaviour and returning their appropriate response (validation errors, unauthorized, missing, etc).
Now this would be easy to do if I wanted to test the CarService
directly since I can inject the client in the parameters, but what if I wanted to test this through the Listings
context?
The only way I can think of, is to pass the client to the context then to the service which seems like a bad idea since the idea of a context would be to hide implementation details from the caller.
from the callers point of view they just want to accomplish something, right, they don’t really care this is going over […] a service
I don’t think I’m trying to test too much and I can understand why people might not want to test their http_client
. I guess I’d like if I could be able to override config based dependency injections per test but thats not possible.
I would appreciate any feedback, blog posts, examples, etc.