woohaaha
Testing models that cannot be created without long chain of dependancies. Tips?
Hi all,
How do you write your context tests (create_thingy(attrs)) when there are a lot of associations that need to be created first?
Here is a contrived example. Let’s says I have a Door model that I’d like to test the color, material, price, etc..
A Door cannot be created without having to first create a Wall
A Wall cannot be created without having to first create a House
A House cannot be created without having to first create a Blueprint
A Blueprint cannot be created without having to first create a Contract
A Contract cannot be created without having to first create a Client
A Client cannot be created without having to first create a Prospect
and on and on… ![]()
I have a method in my Building context that sort of looks like this:
def create_door(attrs \\ %{}) do
%Door{}
|> Door.changeset(attrs)
|> Repo.insert()
end
Ideally in my test I’d like to write something like:
{:ok, door} = create_door(%{price: 1_234, material: "wood", color: "white"})
assert door.color == "white"
However I cannot create the Door without passing in a wall_id and since that field cannot be null I’d need to create a Wall. The creation process then has to go all the way up to … create_user. Surely I’ve missed something huge I can do that will still make me confident in the production code, but won’t make testing difficult.
Any tips or suggestions are greatly appreciated.
First Post!
Mpanarin
I am not very familiar with the approach in phoenix specifically, as I am pretty new to elixir. But this situation is very common in any other language.
I come from python world where this can be generally mitigated by 2 approaches:
- Data migrations. You basically create json or similar files with data, which you add to your test database before running the tests. I don’t really like this, as this is fairly fragile in my opinion
- You create factory classes (or methods|functions, etc.) that generate required objects with required parameters. So if you need a wall for a door your factory function will either get a wall as an argument of create a new one inside it. If to create a wall you need a house, it will create it inside its factory function, etc.
With second approach you will have to do a huge effort of creating this factories if your codebase is fairly big already. But they are easier to maintain as well as way more flexible for your tests )
Popular in Questions
Other popular topics
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
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








