Interfacing to External Dependencies with Behaviours
Testing Elixir — by Andrea Leopardi, Jeffrey Matthias (24 / 80)
👈 Dependency Doubles | TOC | Test Doubles: Stubs, Mocks, and Fakes 👉
The interface that the SoggyWaffle.WeatherAPI module provides is simple, as it’s made of just one function. However, if we expanded the functionalities of the SoggyWaffle.WeatherAPI module, it would be hard to keep SoggyWaffle.FakeWeatherAPI up to datedate to mirror SoggyWaffle.WeatherAPI. This situation is a great use case for behaviours, Elixir modules that define a set of functions (an interface) that other modules can agree to implement. We can define a behaviour that specifies how we want to interface with the weather API and then implement that behaviour both in the real weather API interface as well as the fake one.
integration_tests/soggy_waffle/weather_api_behaviour.ex
defmodule SoggyWaffle.WeatherAPI.Behaviour do
@callback get_forecast(city :: String.t()) ::
{:ok, term()} | {:error, term()}
end
Now we can add the @behaviour SoggyWaffle.WeatherAPI.Behaviour line to both our SoggyWaffle.WeatherAPI module as well as our SoggyWaffle.FakeWeatherAPI module. Having a behaviour for our interface has two benefits. The first is that the behaviour will be checked at compile time; so if we add a function to SoggyWaffle.WeatherAPI.Behaviour but forget to add it to all the modules that implement that behaviour, then…