-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a "Test fixtures" section to a guide #4441
Conversation
The "Test factories" guide shows an example factory that creates test data but then also inserts it directly in the database, bypassing any application logic. This change appends an additional section to the doc describing "Test fixtures" which only create test data and verifies that it only contains valid fields, but relies on existing application functions to insert or update the data. My goal is to elevate the test fixtures approach to the same level as the test factories approach so that people can consider which of the two they prefer to use and have some example code to guide them no matter which they choose.
Hi @eahanson! We can always improve the docs here but we should align on the terms. I personally don’t consider the code you suggested to be different than factories. The difference between fixtures and factories, at least for the purpose of this guide, is that factories are created dynamically, based on functions. I would take fixtures to be more static. In practice we could call all of them fixtures, but in one way or the other, I don’t see a large difference. The current factories code also don’t rule building structs without saving them either. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I find it to be bad practice to rely on context functions for sitting up fixtures, your context functions should be tested, but not by your fixtures.
This is from my experience working on complex projects where we used context functions for our fixtures.
My recommended approach is to use struct and insert!.
%MyApp{} |> struct(attrs) |> MyApp.Repo.insert!
Keep in mind that will also insert any relationship you might have. And you avoid costly context functions with side effects you don’t attend to be part of your test, or it be using transactions and what not that will slow your test suit down.
@josevalim makes sense — what would you think about me replacing my changes with something much smaller along the lines of "instead of having the factory insert into the database directly, you might choose to have it call one of your existing (non-test) functions. Here are a few lines of code for that, and here are the tradeoffs"? My motivation for this change is that some recent projects I worked on started out with an exact copy of the code in this doc but were happier after changing a bunch of code so they could call context functions instead. @Schultzer interesting, did you find other downsides to relying on context functions besides the unwanted side effects and potential slowdowns? (Not that those aren't enough reasons, I just want to understand all the tradeoffs) |
Tight coupling your code is generally viewed as bad practice, not because it inherently is, it can be useful and I practice: code that run together, lives together! For me, fixtures should be without side effects and explicit. |
The "Test factories" guide shows an example factory that creates test data but then also inserts it directly in the database, bypassing any application logic.
This change appends an additional section to the doc describing "Test fixtures" which only create test data and verifies that it only contains valid fields, but relies on existing application functions to insert or update the data.
My goal is to elevate the test fixtures approach to the same level as the test factories approach so that people can consider which of the two they prefer to use and have some example code to guide them no matter which they choose.