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.

1 Like

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.

2 Likes

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.

1 Like

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)
3 Likes