tfwright

tfwright

Dynamic test setup using tags?

Before coming to Elixir I used FactoryGirl in pretty much every project that had data to generate test setup state, so naturally when I started my first Phoenix project I used Bamboo. I didn’t really like the experience nearly as much because you have to manage all the changset related logic yourself which means factories are a lot harder to maintain and/or they’re not as useful. So on my latest project I decided to try using vanilla ExUnit. The main feature Bamboo gives you is the ability to override specific fields with data relevant to what you want to test. You can of course write a function to generate that data but it’s not very DRY. You end up with tests with a half dozen or more functions just to set specific fields, and then you have to either duplicate that in other tests or move them to a shared module. Normally I actively avoid DRY tests, but helper functions feels a bit different.

Of course I could write my own set of very generic functions that accept attrs and call them in the tests so at least there would be less duplication, but I had the thought of using tags to do something similar with even less boiler plate. Basically the idea is to create functions like you normally would, but check for certain tag values in context:

  # Helper module
  def create_source(%{source_count: count} = context) do
    sources =
      0..(count - 1) |> Enum.to_list() |> Enum.map(fn _ -> create_source(context |> Map.drop([:source_count])) end)

    {:ok, sources: sources}
  end

  def create_source(%{user: user} = context) do
    source =
      Repo.insert!(%Source{} |> Map.merge(context |> Map.get(:source_attrs, %{}))
      )

    {:ok, source: source}
  end

  # some test file
  @tag source_count: 5, source_attrs: %{name: "test"}
  test "something about when user already has 5 sources named test", %{user: user} do
    assert %{user: _} = Source.changeset(%Source{user: user}, %{}).errors |> Enum.into(%{})
  end

This isn’t a pattern I’ve used very much so I’m not sure how it will end up working but it feels a lot cleaner to me. What do people think? Is this an abuse of tags? Is there a better way?

First Post!

al2o3cr

al2o3cr

We use tags a lot for test setup at work, some thoughts:

  • it’s good, but can get unwieldy if you try to bunch too many unrelated tests under the same setup - lots of “optional” branches in the setup makes it harder to tell what will actually happen for a test. If you ever want to to write a TEST for your setup, You’re In The Bad Place.

  • overloading a name like create_source seems like a recipe for confusion. If some tests need many sources, split that out to create_sources or something that clearly distinguishes one-vs-many

  • passing the whole context around is usually not what you want since there’s ExUnit plumbing in there (like context.test). Even if it’s a little more verbose, future readers will appreciate if you call out exactly which keys are important (for instance, source_attrs and user in the recursive call to create_source)

Where Next?

Popular in Questions Top

Kurisu
For example for a current url like http://localhost:4000/cosmetic/products?_utf8=✓&query=perfume&page=2, I would like to get: ...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
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
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New

Other popular topics Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
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
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
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
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement