ook

ook

I’m writting tests for a simple module which do HTTP requests.
As recommanded in Mocks and explicit contracts « Plataformatec Blog I use an environnement variable instead of mocking:

defmodule FaLogentriesParserEx do
  @logentries_api Application.get_env(:fa_logentries_parser_ex, :logentries_api)
end

Of course, for dev and prod environment, the module to load in under lib/fa_logentries_parser_ex but since I don’t want test stuff under lib/ I created the “mock” module under test/fa_logentries_parser_ex/logentries_api_fake.exs

My problem: mix test can’t find that module:

  1) test handle_pipeline_status (FaLogentriesParserExTest)
     test/fa_logentries_parser_ex_test.exs:9
     ** (UndefinedFunctionError) function FaLogentriesParserExTest.LogEntriesApiFake.fetch/2 is undefined (module FaLogentriesParserExTest.LogEntriesApiFake is not available)
     stacktrace:
       FaLogentriesParserExTest.LogEntriesApiFake.fetch(1501576495019, 1501576555019)
       (fa_logentries_parser_ex) lib/fa_logentries_parser_ex.ex:10: FaLogentriesParserEx.fetch/1
       test/fa_logentries_parser_ex_test.exs:89: (test)

Could you help me to make that module loadable or advice a better way to test?

Showing Posts 1 to 2

peerreynders

peerreynders

Here is the way I did it with a behaviour:

1.) In the mix.exs use elixirc_paths:

  def project do
    [app: :coffee_fsm,
     version: "0.1.0",
     elixir: "~> 1.4",
     elixirc_paths: elixirc_paths(Mix.env),
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     deps: deps()]
  end

  # Configuration for the OTP application
  #
  # Type "mix help compile.app" for more information
  def application do
    # Specify extra applications you'll use from Erlang/Elixir
    [extra_applications: [:logger]]
  end

  defp elixirc_paths(:test), do: ["lib","test/support"]
  defp elixirc_paths(_), do: ["lib"]

essentially this adds the “test/support” directory where the mock files are

2). in config/config.exs:

case Mix.env do
  :test ->
    config :coffee_fsm, hw: HwMock
  _ ->
    config :coffee_fsm, hw: HwOutput
end

Essentially this will cause test\support\hw_mock.ex to load for testing through @hw_impl in lib\hw.ex - otherwise lib\hw_output.ex is loaded.

3). Meanwhile lib\hw.ex looks like this:

defmodule Hw do
  @hw_impl Application.fetch_env!(:coffee_fsm, :hw)

  defmodule Behaviour  do
    @callback display(f,a) :: :ok when f: String.t(), a: [any()]
    @callback return_change(n) :: :ok when n: non_neg_integer()
    @callback drop_cup() :: :ok
    @callback prepare(t) :: :ok when t: atom()
    @callback reboot() :: :ok
  end

  @spec display(s,a) :: :ok when s: String.t(), a: [any()]
  def display(str, args), do: @hw_impl.display(str, args)
  @spec return_change(n) :: :ok when n: non_neg_integer()
  def return_change(payment), do: @hw_impl.return_change(payment)
  @spec drop_cup :: :ok
  def drop_cup, do: @hw_impl.drop_cup()
  @spec return_change(b) :: :ok when b: CoffeeFsm.beverage()
  def prepare(type), do: @hw_impl.prepare(type)
  @spec reboot :: :ok
  def reboot, do: @hw_impl.reboot()

end 

while test\support\hw_mock.ex looks like this:

defmodule HwMock do
  @behaviour Hw.Behaviour

  use GenServer

  defp forward_pending(pending, pid) when is_pid pid do
    forward_to =
      fn(request, _) ->
        Kernel.send pid, request
        :ok
      end

    pending
    |> Enum.reverse()
    |> Enum.reduce(:ok, forward_to)
  end

  def handle_cast(entry, {:none, pending}) do
    {:noreply, {:none, [entry | pending]}}
  end
  def handle_cast(entry, {pid, pending}) do
    forward_pending [entry | pending], pid

    {:noreply, {pid, []}}
  end

  def handle_call({:forward, pid}, _from, {_, pending}) when is_pid pid do
    forward_pending pending, pid

    {:reply, :ok, {pid, []} }
  end
  def handle_call({:forward, _}, _from, {_, pending}) do
    {:reply, :ok, {:none, pending} }
  end
  def handle_call(:clear, _from, {pid, _}) do
    {:reply, :ok, {pid, []} }
  end

  defp log(entry) do
    GenServer.cast __MODULE__, entry
  end

  def init(_args), do: {:ok, {:none, []}}

  # public interface
  def start_link, do: GenServer.start_link __MODULE__, [], name: __MODULE__

  def clear(pid) do
    GenServer.call __MODULE__, :clear
  end

  def forward(pid) do
    GenServer.call __MODULE__, {:forward, pid}
  end

  # implementing "Hw"" behaviour
  def display(str, args) do
    log { :display, [str, args] }
    :ok
  end

  def return_change(payment) do
    log { :return_change, [payment] }
    :ok
  end

  def drop_cup do
    log { :drop_cup, [] }
    :ok
  end

  def prepare(type) do
    log { :prepare, [type] }
    :ok
  end

  def reboot do
    log { :reboot, [] }
    :ok
  end

end
ook

ook OP

Thanks a lot peerreynders, elixirc_paths was perfectly what I needed. I’ll check your way to go with behavior, too.

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews