When testing controllers it can be useful to have some data in the test database. And sometimes you might want to test the data creation. What is the correct way to set this up? A test for controllers should test if the create
function of the controller is working, not the model.
As an example I want to test a Session controller and I have two tests. One is testing that a created user can login. The other that he cannot if the password is wrong. Both rely on a user being in the database. How I deal with it now is to create the user first:
defmodule MyApp.SessionControllerTest do
use MyApp.ConnCase
alias MyApp.Admin
@valid_attrs %{email: "[email protected]", name: "John Doe", password: "goodpassword", password_confirmation: "goodpassword", password_hash: "somecontent", username: "username"}
@invalid_attrs %{}
setup do
{:ok, conn: put_req_header(conn, "accept", "application/json")}
end
test "admin can login after creation" do
conn = post conn, admin_path(conn, :create), admin: @valid_attrs
body = json_response(conn, 201)
assert Repo.get_by(Admin, email: @valid_attrs[:email])
conn = post conn, session_path(conn, :create), %{data: %{attributes: %{email: @valid_attrs[:email], password: @valid_attrs[:password]}}}
body = json_response(conn, 201)
assert body["data"]["token"]
end
test "login with wrong password returns an error" do
conn = post conn, session_path(conn, :create), %{data: %{attributes: %{email: @valid_attrs[:email], password: "wrongpassword"}}}
body = json_response(conn, 403)
assert body["error"]
end
end
If I now add a uniqueness restrain on my Admin
model this could potentially get messy since whenever I need a user in the database I have to make sure that the test isn't failing because of this constraint but because something in the tested controller is wrong. Also it isn't clear in which order the tests are run and staying consistent with the data creation over several tests seems like a nightmare.
I either want one place where I define in the beginning which Data is created. Or use mocks for Controller testing.
How is this possible?
Use the setup
function for add some data to your database.
setup do
Repo.insert!(%User{id: 1, password: "somepassword", ....})
....
:ok
end
The setup
will be called before every test.
See ExUnit hexdocs for more information.
For run the tests step by step in synchronous mode add async: false
to use call.
defmodule MyApp.SessionControllerTest do
use MyApp.ConnCase, async: false`
But I think it's better to run the tests without dependencies to other tests.
defmodule MyApp.SessionControllerTest do
use MyApp.ConnCase
alias MyApp.Admin
@valid_attrs %{email: "[email protected]", name: "John Doe", password: "goodpassword", password_confirmation: "goodpassword", password_hash: "somecontent", username: "username"}
@invalid_attrs %{}
setup do
Repo.insert!(%User{email: "[email protected]", password: "somepassword", ....})
{:ok, conn: put_req_header(conn, "accept", "application/json")}
end
...
test "login with wrong password returns an error" do
conn = post conn, session_path(conn, :create), %{data: %{attributes: %{email: "[email protected]", password: "wrongpassword"}}}
body = json_response(conn, 403)
assert body["error"]
end
end
Hope it helps.
Little bit late to the party but it might help others.
I would suggest using a ex_machina factory library. https://github.com/thoughtbot/ex_machina With it you can define and create test data in one place.
Define factories like so:
defmodule MyApp.Factory do
# with Ecto
use ExMachina.Ecto, repo: MyApp.Repo
# without Ecto
use ExMachina
def user_factory do
%MyApp.User{
name: "Jane Smith",
email: sequence(:email, &"email-#{&1}@example.com"),
}
end
def article_factory do
%MyApp.Article{
title: "Use ExMachina!",
# associations are inserted when you call `insert`
author: build(:user),
}
end
def comment_factory do
%MyApp.Comment{
text: "It's great!",
article: build(:article),
}
end
end
And creating a record would be:
insert(:comment, article: article)
You can also build a record (unsaved)
build(:user)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With