...

/

Finer Control over Dependency Injection

Finer Control over Dependency Injection

Learn how Dependency Injection can be fine-tuned.

An alternative to injecting a whole function is to pass in a single value. An example we might see in code is when the outside dependency is the system time. If our code under test needs to do something with system time, it’s very difficult for our tests to assert a known response or value unless we can control system time. While controlling our code’s concept of system time is easy in some languages, it isn’t in Elixir. That makes this scenario a perfect candidate for injecting a single value.

The following code allows for an injected value, but it defaults to the result of a function call if no parameter is passed:

Press + to interact
#file path -> soggy_waffle/lib/soggy_waffle/weather.ex
defmodule SoggyWaffle.Weather do
@type t :: %__MODULE__{}
defstruct [:datetime, :rain?]
@spec imminent_rain?([t()], DateTime.t()) :: boolean()
def imminent_rain?(weather_data, now \\ DateTime.utc_now()) do
Enum.any?(weather_data, fn
%__MODULE__{rain?: true} = weather ->
in_next_4_hours?(now, weather.datetime)
_ ->
false
end)
end
defp in_next_4_hours?(now, weather_datetime) do
four_hours_from_now =
DateTime.add(now, _4_hours_in_seconds = 4 * 60 * 60)
DateTime.compare(weather_datetime, now) in [:gt, :eq] and
DateTime.compare(weather_datetime, four_hours_from_now) in [:lt, :eq]
end
end

In the above code, in line 8, we can see that without a value passed in, the result of DateTime.utc_now/0 will be bound to the variable datetime. Our tests will pass ...