ArthurMmn
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) :
- Duplicating all callback with and without the optional arguments (sad when there is a lot of callbacks)
- 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 ?
Trending in Questions
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
Hi everyone,
I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding.
I sta...
New
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
Documentation
While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
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
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New
Other Trending Topics
Edit: 2026 May 15 - This post is archived.
Mob is alive!!
Main docs: mob v0.7.11 — Documentation
A bit of explanation for the slightly c...
New
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
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
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
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #ai
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #elixirconf-eu
- #metaprogramming
- #hex










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
LostKobrakai
You’re essentially running into the fact that behaviours do not have optional parameters. There’s just fixed arity callbacks. Mox being driven by behaviours inherits that. But you could always place an interface with optional parameters in front of code calling only the “fully arity” behaviour callback implementations. That’s e.g. how ecto does it.
E.g.
ArthurMmn
I guessed there was not much more to find here.
Any thoughts on why callbacks were never implemented with optional parameters ?
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
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
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
lud
Would you be able to define a behaviour like this?
If yes then there is no built in mechanism to automatically pass the arguments into the implementation modules
Because the behaviours are not called, your code will call the module directly:
So the
Implmodule must have agreeting/1function.You can of course define different functions in the behaviour
Yes and there is no mechanism to define default values from outside of a module, so it must be the implementation module.
A pattern I see a lot is using the behaviour as the API:
mudasobwa
In my humble opinion, this sentense puts the cart before the horse. Like one never tests private functions, one arguably should not mock anything but behaviours. Mocking arbitrary functions just makes zero sense, simply revealing the design flaw, which would definitely raise later.
funboy
Interesting point!
Let me explain my use case:
I often use it for unit tests where I want to focus purely on the logic inside a single module. For example, I don’t want to spin up the processes that call HTTP services or the database - those dependencies would each need their own mocks every time I test a simple function like calc/0.
For that unit test, I’d rather just mock the return value of Foo.points/0 instead of setting up deeply nested mocks for everything under it or adding a new behaviour solely for test purposes.

of course those dependent processes are already covered by integration test validating that everything works together
So in short: Mimic is convenient when I want to test simple logic without introducing extra behaviours or large amounts of test setup with Mox for deeply-nested behaviour based (http/db etc) dependencies
Let me know if I’m missing sth
mudasobwa
Well, I might not be the best person to discuss testing techniques with in the first place. I was always loudly against the “test for the sake of tests,” and 100% coverage, and whatnot on that matter.
I have a strong opinion that while unit tests are great during development stage, they are a burden for both regression and refactoring. I never need to constantly validate that
calc/0returns3. It just makes no sense, because if it did, I’d write it asdef calc, do: 3.What makes sense to test, is …ahem… how your app behaves. What is literally covered by erlang behaviour paradigm. Your
Foo.points/0should not be deadly nailed, because tomorrow you’ll discover a better, faster, or cleaner way to calculate points, and you surely won’t want to overwrite the existing implementation, at least during development and for benchmarks.Every time I find myself unit-testing a function in the wild, I ask, why, for God’s sake I want to bring a fragile test, depending on my current implementation, to the test suite? The answer is always either “Huh, that’s a behaviour then,” or “I should make this function private and test its implication.”
funboy
Me too!
100% agree!
That unit test checks if calculations are correct - you can refactor calc function later - but the test will stay the same - calc function for same data should return the same output - and testing if calculations are correct it’s worth to check in unit test I guess
Maybe a more abstract example would illustrate it better, though it still might be a bit lacking - sorry.
In my experience, clean, small, fast, async unit tests are far less fragile than test suites that require dozens of deeply-nested behaviour mocks just to verify some calculation logic/ output

but I might be wrong
I see u don’t like unit tests and you have every right to