wfgilman

wfgilman

Can you define a behaviour in the same module that implements it?

I have a behaviour for which I need to implement real functions and mock versions for testing. Right now I am using three modules to do this: the behaviour, the live and the mock. It makes my file structure and naming kind of a pain.

Is something like this possible?

def MyApp.MyModule do
  @behaviour MyApp.MyModule

  @callback myfunction(atom, list) :: :ok | :error
  def myfunction(arg, opts) do
    ...
  end
end

The Ecto.Repo behaviour has something similar where the default function implementations are in a __using__/1 macro, but I don’t need any code injection.

If not, why?

Most Liked

wfgilman

wfgilman

I realized that after I submitted the topic late Friday afternoon :joy:

The mocks are for an application that talks to a third party API. I’m trying to implement the application in a way that allows for proper testing.

I built an Elixir library for Plaid, the financial data service. I’m using this application as part of an umbrella application that is my larger project. I’ve since refactored the Plaid application to implement the recommended best practice for testing functions that call a third party. Here is a gist that shows the implementation for the Plaid /connect endpoint refactored to use this best practice. A single endpoint contains three files in the following directory structure:

+ lib
   + plaid
     + connect
       - live.ex
       - mock.ex
     - connect.ex

Plaid.Connect.ex is the behaviour and documentation
Plaid.Connect.Live.ex is the implementation
Plaid.Connect.Mock.ex is the mock

In my dev and test environments I can reference the appropriate module using the config.

This works great, but it seems like it can be refactored to something like I outlined in my first post. I’m so interested in doing this because I’d like to deploy this testing practice in other applications of my umbrella project. All the applications talk to each other, and I need to mock those client API functions in order to write proper unit tests. I’d like to be able to do so in a way that allows me to enforce explicit contracts without creating a complicated directory structure. If I can put the behaviour and implementation in the same module, then I can put all the mocks in another location (like a testing folder) which makes things clearer:

+ lib
  + plaid
    - connect.ex
+ test
  + lib
  + support
    + mock
      - connect.ex

Plaid.Connect.ex is the behaviour and implementation
Plaid.Mock.Connect.ex is the mock

hubertlepicki

hubertlepicki

I use behaviours with my modules exactly the same way, and the reason is also testing. I am using mox for testing and I do declare my behaviours and implementations in the same file. In fact, a behaviour is declared next to the function I am about to write.

I just use the behaviour to make sure my mocks follow the same interface as implementations.

wfgilman

wfgilman

bump :blush:

OvermindDL1

OvermindDL1

Weekends are slow. ^.^

However you should be able to have a module that both defines and implements a behaviour, I used to do it back in the Erlang days for a few ‘default behaviour’ things.

Better question though, why? There are almost always better ways. :slight_smile:

You should never really mock functions, ever, you can mock a process, but if you are mocking functions then something is almost certainly done wrong. What are you trying to actually achieve with a full example we can run ourselves? :slight_smile:

wfgilman

wfgilman

Any thoughts on this? :039:

Where Next?

Popular in Questions Top

logicmason
Hi there, I'm working through my first release with elixir/phoenix. I've built a release with distillery and found that it crashes when I...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
mathew4509
I have a list say x = ["23gh", "56kh", "97mh"] I would like to pass each element to Val in each iteration. Say, in iteration 1 -------...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
hpopp
To simplify some tasks at work, I wrote and published this package yesterday. It’s a simple macro that enables Access behaviour on struct...
New
Codball
Mix format works fine if run from the cmd. I’ve followed this to facilitate the implementation into VSC which involves downloading an ext...
New
Mooodi
Given a string, how can I get access to its character by index? Enum.at("my_string", 2) doesn't work. Or rather, not char, but a substr...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3268 119930 1237
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
AstonJ
You’re a programmer, so you don’t need spoon feeding with the conventional drivel about “this is an integer.” No. You need to know what’s...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
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
johnnyicon
Hi all, I've just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I'm trying to use Postg...
New
magnetic
Hey :wave:t3: Elixir community, I’ve been learning Elixir, and working on some side projects. My editor of choice is VSCode, and althoug...
New

We're in Beta

About us Mission Statement