ArthurMmn

ArthurMmn

Conflicts between Mox, behaviours and optionnal arguments

I have a behaviours with lots of functions. Each pass an arguments and an optional keyword list of options. And I found myself in this weird situation where testing with Mox introduce some unsatisying results.

A reduction of the problem :

defmodule MyBehaviour do
  @callback greet(name :: String.t(), greeting :: String.t()) :: String.t()
end

defmodule MyModule do
  @behaviour MyBehaviour

  @impl true
  def greet(name, greeting \\ "Hello") do
    "#{greeting}, #{name}!"
  end
end

And a test like this

import Mox

defmock(MyMock, for: MyBehaviour)

MyMock
|> expect(:greet, fn name -> "Hello #{name}" end)

result = MyMock.greet("World")

It fails because the mock does not know any function of arity 1 called greet.

** (ArgumentError) unknown function greet/1 for mock MyMock
    (mox 1.2.0) lib/mox.ex:681: Mox.add_expectation!/4
    (mox 1.2.0) lib/mox.ex:549: Mox.expect/4

If I test instead

import Mox

defmock(MyMock, for: MyBehaviour)

MyMock
|> expect(:greet, fn name, _ -> "Hello #{name}" end)

result = MyMock.greet("World")

It obviously fails, because the function with one argument is never mocked.

** (UndefinedFunctionError) function MyMock.greet/1 is undefined or private. Did you mean:

      * greet/2

    MyMock.greet("World")

Which leaves me with two choices (I think) :

  1. Duplicating all callback with and without the optional arguments (sad when there is a lot of callbacks)
  2. Removing the “optional” from the arguments and always calling the two arity functions.

I chose option 2 with a lack of enthusiasm, anyone in the same situation chose a different solution ? Or had a better way of dealing with the situation ?

Most Liked

LostKobrakai

LostKobrakai

Optional parameters are a compile time construct of elixir. Behaviours are an erlang level feature, which existed even before elixir existed. Generally I’d keep the interface to multiple implementations as simple as possible and handle the optional stuff before or after that interface.

garrison

garrison

Expanding on the above, default args are not actually “real”. They are just syntax sugar for additional function heads.

I suppose that sugar could be extended to callbacks, though it might be a bit confusing to generate multiple callback “heads”. The abstraction starts to leak.

And who defines the default arg’s value? The callback, or the implementation? It’s messy.

funboy

funboy

you can try to use GitHub - edgurgel/mimic: A mocking library for Elixir · GitHub
there is no mess with creating behaviours only for testing purposes :smiley:

Where Next?

Popular in Questions Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> somethi...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New

Other popular topics Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31307 143
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New

We're in Beta

About us Mission Statement