kostonstyle

kostonstyle

Why avoid mocks

Hi all

I am reading the phoenixframework book and says in the testing section, that we should avoid mocks for testing why?

Thanks

Marked As Solved

rrrene

rrrene

Credo Core Team

José - the creator of Elixir - explained it beautifully here:

http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/

Also Liked

josevalim

josevalim

Creator of Elixir

Firstly, the “verb/noun” distinction has a root in OOP and I believe it is not relevant in Elixir, mocking or not.

That’s pointing to the wrong direction. First of all, OOP and FP are not mutually exclusive domains. They are properties shared by both paradigms. I will come back to this later on. The “verb/noun” guidance was not meant to be at the abstraction level but a guidance on how you are expressing your intent in the code.

The latter uses an implementation that is in fact the same as something I define in a mocking library, only adding my own potential bugs.

That’s one of the points of the linked article. You can use mock libraries as long as they are helping you build mocks rather than dynamically replacing existing components. If your mock library is leading you down the former path, then please go ahead! The article is far from a call to “forget mocks because they are bad”.

The article talks about dependency injection - which is based on “interfaces” in other languages and is re-defined as “protocols” in Elixir. Both are OO concepts.

Elixir protocols are not interfaces. Behaviours would be the closest thing to interfaces. However, typed contracts are not exclusive to OO languages. Protocols build on top of behaviours to add data-type polymorphism (a form of ad-hoc polymorphism). Polymorphism is not a concept exclusive to OO as well. Protocols in Elixir provide the same kind of polymorphism as Haskell type classes.

That brings me to the first point: why does it even matter if it is an OO concept? Being an OO concept doesn’t invalidate it nor implies it is a bad concept. In fact, the paper that introduced type classes references polymorphism in OO languages multiple times and does a good job in explaining how type classes address issues commonly found in OO implementations. Similar concept with different implementations.

That’s why I said this discussion is pointing to the wrong direction. Maybe there is a valid argument against those constructs in the context of testing but “because it is OO” is certainly not the reason (nor it is true).

I never liked dependency injection because it changes the design of a program to accomodate testing. In the functional paradigm we should aim at modules/functions that are free of side effects and dependency injection is a side effect.

If by side-effect you mean the functional definition of side-effects, dependency injection is not a side-effect. It would only be a side-effect if the code you are invoking contain side-effects. In languages like Haskell you can do dependency injection via higher order functions or type classes without involving a monad.

On the other hand, I completely understand how “dependency injection” can be a source of confusion. The page for dependency injection in Wikipedia is quite convoluted and I find it personally hard to see how that would map to “passing a function or a module as argument” in Elixir.

Finally the article also answers why I don’t personally agree with the “dependency injection changes the design of a program to accomodate testing”. A test is a consumer of your code like any other API. If your code is hard to test, it will very likely be hard to extend. Sometimes that’s fine, we don’t want all code to be extensible, that would be a nightmare to reason about. But if you feel like you need to make the code more extensible to properly test it, it is very likely the extension will be useful beyond testing. The point of the blog post is to help you reason about those trade-offs rather than find one size fits all solution.

15
Post #9
michalmuskala

michalmuskala

I would strongly disagree that dependency injection is an OO concept. In fact I will even say that dependency injection is bread and butter of functional programming. How? Higher order functions. What is a higher order function if not a function where we “inject” the dependency - the code that executes some algorithm or performs some computations.

Injecting whole modules is no different, not really. A module is just a set of functions. Passing a module is a convenient way of passing multiple named functions. Having said that, passing the dependency through application environment is indeed a side-effect and may be not considered a good style, but it’s very simple and convenient.

When it comes to testing and it’s presence or not - I think this depends hugely on the company. I’m fortunate to work in one that requires thorough testing of all the code - code that is not tested is simply not shipping to production. In fact, working on Phoenix APIs, I rarely start the application - most of the time I work just on the tests.

rrrene

rrrene

Credo Core Team

Hard to argue with that.

josevalim

josevalim

Creator of Elixir

I partially agree. If the value never changes, it will be side-effect free. That’s exactly what happens when the application environment is read at compile-time rather than runtime. The behaviour at runtime is guaranteed to be the same.

archan937

archan937

I would rather use https://github.com/archan937/mecks_unit … (async) mocking using the Erlang :meck library. I don’t want to compromis (by altering my initial code and making things interchangeable) because I just want to unit test my code.

Where Next?

Popular in Questions Top

yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
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
Fl4m3Ph03n1x
Background Let’s assume I have a typical GenServer that receives messages as requests, does some operation in a DB and returns responses....
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
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
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
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
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
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement