Testing schema

Hello everyone! I’m new in Phoenix, trying to make blog by reading this tutorial. Now I’m at step 3: Step 3: Saving a Password Hash instead of a Password

I had change schema lib/blog/users/user.ex from

  schema "users" do
    field :email, :string
    field :password_digest, :string
    field :username, :string

    timestamps()
  end

  @doc false
  def changeset(user, attrs) do
    user
    |> cast(attrs, [:username, :email, :password_digest])
    |> validate_required([:username, :email, :password_digest])
  end

to

  schema "users" do
    field :email, :string
    field :password_digest, :string
    field :password, :string, virtual: true
    field :password_confirmation, :string, virtual: true
    field :username, :string

    timestamps()
  end

  @doc false
  def changeset(user, attrs) do
    user
    |> cast(attrs, [:username, :email, :password, :password_confirmation])
    |> validate_required([:username, :email, :password, :password_confirmation])
    |> hash_password
    end
    defp hash_password(changeset) do
      changeset
      |> put_change(:password_digest, "ABCDE")
  end

Now I’m getting failure in schema test:

  1) test users get_user!/1 returns the user with given id (Blog.UsersTest)
     test/blog/users_test.exs:27
     Assertion with == failed
     code:  assert Users.get_user!(user.id) == user
     left:  %Blog.Users.User{
              __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
              email: "some email",
              id: 140,
              inserted_at: ~N[2020-03-17 10:28:27],
              password: nil,
              password_confirmation: nil,
              password_digest: "ABCDE",
              updated_at: ~N[2020-03-17 10:28:27],
              username: "some username"
            }
     right: %Blog.Users.User{
              __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
              email: "some email",
              id: 140,
              inserted_at: ~N[2020-03-17 10:28:27],
              password: "test1234",
              password_confirmation: "test1234",
              password_digest: "ABCDE",
              updated_at: ~N[2020-03-17 10:28:27],
              username: "some username"
            }
     stacktrace:
       test/blog/users_test.exs:29: (test)

But I can’t get it, where I need to make changes to pass test.

And also I understand, that tutorial is outdated, because in many places I’ve met differences. Please, help me examine, what I’m doing wrong

Hello and welcome…

You are following a tutorial with an old Phoenix version… I would not recommend it because Phoenix 1.2 is very different from what we use now.

For your test… You are comparing a newly created user, with one got from db. And the last one does not have virtual attribute set.

You might compares on attributes instead, password_digest for example.

I understand that I can use assertion of all attributes exclude that, but I think it is not correct

But the users are not the same (one has virtual attributes set)… this would be also the case between a User, and the same User with preloads.

Yes, I get it, maybe elixir or phoenix has embedded tools or function which can exclude virtual attributes? Something like user.except(:password, :password_confirmation)

If You look at generated tests, they compare on attributes…

Otherwise it is not that hard to do partial pattern match.

thank you!

Don’t get hung up on this too much. Comparing full objects coming from the DB isn’t a good practice. F.ex. Elixir puts the :__struct__ special key inside them which can change in the future, can include data that’s specific for each instance etc.

Just compare on a subset of the important attributes and you’re good:

@attrs [:email, :password_digest, :username]
assert Map.take(expected_user, @attrs) == Map.take(actual_user, @attrs)