hauleth

hauleth

Split Thread: Fixtures vs Factories in Elixir

Use factories and not fixtures

Gods, I cannot even express how much I disagree with it.

Most Liked

josevalim

josevalim

Creator of Elixir

I will add some cents to the discussion that I haven’t seen mentioned yet. Below, I will be talking about database-backed fixtures (and not necessarily fixtures as a whole):

  1. One of the downsides of fixtures is that it is shared data across all of your tests. So sometimes you will change your fixtures, because you need new data to be used in some new tests, and other tests may now fail. This gets worse if projects define a large amount of fixture data. The correct approach, as mentioned earlier, is to define fixtures for a basic feature set that will be shared across all tests.

  2. The particular fixtures implementation in Rails caused some issues because referential integrity and data validations are disabled or not really used in Rails, so you could easily end-up with invalid data or data that would never exist in the database through the regular application workload.

  3. It is actually super straight-forward to have fixtures in Ecto: just write to the database in your test_helper.exs before you start the SQL sandbox.

Finally, a summary that was given to me a long time ago that explains when to use fixtures vs factories well is:

  1. Use fixtures for the setup data (i.e. the data you need to define before you can start writing your test)
  2. Use factories for the data under test, especially because you want the data being tested close to the test itself

In my opinion, factories are actually easier to get started as they require less discipline (with bigger costs in the long term), while fixtures are really easy to mess up at the beginning (but pay off if well-structured).

BartOtten

BartOtten

Please try; otherwise your comment is nothing but negative energy.

TheFirstAvenger

TheFirstAvenger

My .02 on fixtures vs factories:

My problem with Fixtures is that it buries the logic that you are testing. Repeatedly in my career I have jumped in to work on a fixture-using project, and without fail I end up wasting way too much time on what should be a simple task of fixing or updating a test, because the logic of what exactly is being tested was not clear in the test, it was buried implicitly in the fixture data.

For example, if you were to come across this test which is all of a sudden failing, which relies on fixtures, what would you do to fix it?

test “returns confrazzled users” do
  assert [%{id: 1}, %{id: 3}] = Confrazzler.get_confrazzled_users()
end

From the test, it is unclear what is being tested, or why it is failing. You could look in the fixtures, but even then it most likely wouldn’t be clear what exactly is supposed to be testing. You would have to dig into the actual code to figure out what get_confrazzled_users actually does. In a recent project, the function being tested used a 100 line SQL statement. It was basically impossible to reverse engineer what exactly was being tested.

Now, if it were written with factories, you would instead see this code:

test “returns confrazzled users“ do
  %{id: id1} = insert(:user, frazzled: “con”)
  %{id: id2} = insert(:user, frazzled: “pro”)
  %{id: id3} = insert(:user, frazzled: “con”)

  assert [%{id: ida}, %{id: idb}] = Confrazzler.get_confrazzled_users()
  assert Enum.sort([ida, idb]) == Enum.sort([id1, id2])
end

In the factory test, the setup is clear and explicit, and part of the test. There is no digging in fixtures to figure out what the implicit assumptions are, or combing through 20 fields to try and figure out which field(s) are actually being tested in the current test, because the answer to that is clear in the setup inside the test. It is easy to understand that this test is testing that get_confrazzled_users returns users where their frazzled field is “con”.

In the fixture test, frazzled: “con” was set for id 1 and 3 in the fixture. That fact was known by the person who wrote the test initially, but it is hidden knowledge to everyone else reading it, and hidden to anyone who subsequently needs to update the fixtures.

Beyond the issue of fixtures burying logic, there have been plenty of issues I have caught because the factory was using randomly generated data and triggered an edge case I didn’t think of, which the static fixture never would have covered.

Where Next?

Popular in Discussions Top

andre1sk
A big advantage to Elixir is all the distributed goodness but for many applications running on multiple nodes having integrated Etcd, Zoo...
New
jeramyRR
This is an interesting article to read. Elixir’s performance, like usual, is excellent. However, it seems like the high CPU usage is co...
New
MarioFlach
Hello, I want to share a project I’ve been working on for a while: https://github.com/almightycouch/gitgud Background Some time ago I ...
New
axelson
Decided against including more info in the title, but the gist is that Plataformatec sponsored projects will continue with the assets bei...
New
AlexMcConnell
The reason that Rails is as popular as it is is because it’s very easy for relatively inexperienced developers to get a lot of work done....
588 19568 166
New
Crowdhailer
I’ve been hearing much about the new formatter and it’s something I have been keen to try. I find examples buy far the most illuminating...
248 19204 150
New
crabonature
I’m still quite new to Elixir. As I understand we got in Elixir “multi guards” as convention to simplify one large guard with or’s?: de...
New
shishini
I think this twitter post and youtube video didn’t get as much attention as I hoped I am still new to Elixir, so can’t really judge ...
New
pdgonzalez872
If this has been asked here before, please point me to where it was asked as I didn’t find it when I searched the forum. Maybe a mailing ...
New
paulanthonywilson
I like Umbrella projects and pretty much always use them for personal Elixir stuff, especially Nerves things. But I don’t think this is ...
New

Other popular topics Top

Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39297 209
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I’m a nov...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New

We're in Beta

About us Mission Statement