Fl4m3Ph03n1x
Background
I have a behaviour that has some functions inside it, so that modules that implement it can use them:
defmodule MyBehaviour do
#some callback for other modules to implement
@callback match(data :: any) :: boolean
defmacro __using__(_opts) do
quote do
@behaviour MyBehaviour
def build_query(some_str) do
String.slice(some_str, 1..-1) #random op on string
end
end
end
end
Problem
However, I need to test if build_query is working properly. I can’t invoke it and test it normally via MyBehaviour.build_query/1 because technically it doesn’t belong to the behaviour, it is instead inside the macro.
Question
How do I access MyBehaviour.build_query/1 in order to test it?
Trending in Questions
Hey guys,
I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly
Do you guys have any suggestions what is the best prac...
New
Hello!
Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app.
I creat...
New
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New
Anyone here using Honeybadger?
My Honeybadger account is being overwhelmed with noise from some bots. Seeing a lot of
Bandit.HTTPError...
New
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
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
Other Trending Topics
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hobbes is a low-level distributed database for the Elixir programming language.
Hobbes provides a simple, safe, and scalable storage lay...
New
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
There are three potential reasons for members of this forum to have a look at https://vutuv.de
You are tired or annoyed of LinkedIn.
Yo...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixir-ls
- #ai
- #elixirconf-us
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
LostKobrakai
If the function does not need data from within the macro just move the function in your behaviour and let the macro import it. If if does need data from the macro, then you need to call the macro from some module to test it on.
NobbZ
This is one way.
The other way (which I’d prefer) were to not inject it, but import it and also make it unimportable through options.
devonestes
If the function isn’t some default implementation for the required callbacks for your behaviour, I would contend that it probably shouldn’t be a part of the
__using__macro at all. No need to even import it in the__using__macro, as that will duplicate the implementation of that function across all modules thatusethat behaviour.I would (personally) do this:
Then you test that function directly as any other function, and you don’t have duplicate implementations of the same functionality (which is basically what’s happening when you
importanything). If your implementations of that behaviour need variations on that function, you can replaceMyBehaviour.build_query/1with a locally defined variation on that function.Fl4m3Ph03n1x
@NobbZ
This is an approach I also took. However I do have the feeling that instead of manually making a FakeImplementor ( which is in reality a mock ), I should be using real mocks, in specific, I should be using the library mox with contracts and all. However I am not yet up to that level and so for the time being I need an intermediate solution.
@devonestes
This was actually my original approach. Since every module that implements this behaviour will likely use this function, I saw it as a good idea to simply put it inside the macro.
My original idea here is to follow something among the lines of
use GenServer. You can access and use a ton of their functions, but you don’t do it viaGenServer.some_function, you just callsome_functionand you are done with it.My idea would be to do the same with a simple module, but I don’t quite know how to test it. How did the guys from Elixir team test their implementations? By using FakeImplementors? Mox? There has to be a way.
LostKobrakai
Elixir also uses a module created just for testing: elixir/lib/elixir/test/elixir/agent_test.exs at 7f4756d401a4e59f531484f96990f710d41be540 · elixir-lang/elixir · GitHub
I mean that’s in the end exactly what you want to make sure works: Using it in another module. It’s easy to do so why not test it that way?
NobbZ
What ton is this? I’m not aware of a single one…
edit
Took a look at the source code,
GenServerdoes not put anything into your module, except for thechild_specand the default callback implementations:devonestes
They don’t test behaviour definitions in Elixir, they only test the actual implementations. For example, they have a
Calendarbehaviour, but they only test the different calendars themselves, not the behaviour on its own using a fake implemenation or something. IMHO this is the right thing to do. Test the implementations, not the behaviour.Fl4m3Ph03n1x
How do you know if
handle_callis correctly implemented)?Child_spec? ( how would you test them? )You automatically include them in your code when you
usethe GenServer. These functions are tested, right?This is what I am trying to understand. Is it only possible to test functions inside macros by using a FakeImplementor? If so, Wouldn’t it be better to use moxx ?
PS: I do agree with the overall notion that one should extract the function out of the macro and into the behaviour, but I am trying to understand how one would test functions inside macros.
NobbZ
The default implementations are not tested at all, they just logg if they were called to avoid a spilling message queue, as soon as you see such a message in production, you should implement a proper handler that deals with those messages. If you have at least one handle_X, the default one isn’t used any more and your
GenServerwould crash on an unknown message for that handler.child_specis probably not tested as well, it just returns a constant map and doesn’t change.If at all you’d test the
__using__macro if it creates thechild_specfunction correctly, as you need to specify some things thatchild_specshall return as an argument to theuse.Fl4m3Ph03n1x
Alright. So what I get from this discussion is the following:
My last question, is putting functions inside the use macro considered an anti-pattern in this community?
What are the cases one should and should not do it?
I am merely asking for online resources to read, since I failed to encounter any.