I’m following Programming Phoenix and code along but I try to add something on my own to learn by experimenting, and I need some advice. I don’t know how to make proper “fixture” in controller test.
My Video model looks like this:
defmodule Rumbl.Video do
use Rumbl.Web, :model
schema "videos" do
field :url, :string
field :title, :string
field :description, :string
belongs_to :user, Rumbl.User
belongs_to :category, Rumbl.Category
timestamps()
end
@doc """
Builds a changeset based on the `struct` and `params`.
"""
def changeset(struct, params \\ %{}) do
struct
|> cast(params, ~w(url title description category_id))
|> validate_required([:url, :title, :description, :category_id])
|> assoc_constraint(:category)
end
I added assoc_constraint(:category) to make sure that every video is saved with category_id. Category model is simple, it has only name.
My test looks like this:
defmodule Rumb.VideoControllerTest do
use Rumbl.ConnCase
alias Rumbl.Video
@valid_attrs %{url: "http://youtu.be", title: "vid", description: "a vid"}
@invalid_attrs %{title: "invalid"}
..........
@tag login_as: "max"
test "creates user videos and redirects", %{conn: conn, user: user} do
category = insert_category(%{name: "Drama"})
attrs = Map.merge(@valid_attrs, %{category_id: category.id})
conn = post(conn, video_path(conn, :create), video: attrs)
assert redirected_to(conn) == video_path(conn, :index)
assert Repo.get_by!(Video, @valid_attrs).user_id == user.id
end
I don’t want to repeat that part in every test that may need that, because it does not look DRY:
@valid_attrs %{url: "http://youtu.be", title: "vid", description: "a vid"}
...
category = insert_category(%{name: "Drama"})
attrs = Map.merge(@valid_attrs, %{category_id: category.id})
So the question is, what can I do, to ensure that some, chosen by me test will have Category? In Rails using FactoryGirl I’ll would just create a lazy evaluated Category, and also lazy evaluated @valid_attrs with that particular category_id. And the test would only hit the database (ie. create category and return it’s id) only when i would use that @valid_attrs. But how can I do it in Phoenix, so that I won’t have to repeat creating category and merging params map with proper category_id?
Is making a private function like this:
defp valid_params_map do
category = insert_category(%{name: "Drama"})
Map.merge(@valid_attrs, %{category_id: category.id})
end
Is a proper way? Or maybe I should do something else? What is a proper strategy for that? How do you do it?