like app logic, must be Fast, Isolated, DRY, Repeatable
ensure your test config are as you need, test.exs
ExUnit.startensures it's ready, placed in TestHelper
- structure
defmodule MyModuleTest do
use ExUnit.Case, async: true
setup, do: :ok
test "#myaction" do
end
...
- to run
mix test;mix test my/module_test.exs:6for specificity
- add
user_fixtures/1&video_fixture/1at test_helper.exs
-
Phoenix generates a module test/support/data_case.ex serving a foundation for tests that interact with DB
-
data_casehandles setup/teardown of DB integrating withEcto.Sandboxallowing concurrent transactional tests (transactional tests run tests then rollback changes made during test) -
add
import Videologue.TestHelperstousing do .. end
- add accounts_test.exs for
register_user/1with different input validities
add
, async: truetouse Videologue.DataCase
defmodule Videologue.AccountsTest do
use Videologue.DataCase, async: true
alias Videologue.Accounts
alias Videologue.Accounts.User
describe "register_user/1" do
@valid_attrs %{username: "testuser", name: "test user", password: "cryptography"}
@invalid_attrs %{}
test "with valid data inserts" do
assert {:ok, %User{id: id} = user} = Accounts.register_user(@valid_attrs)
assert user.name == "test user"
assert user.username == "testuser"
assert [%User{id: ^id}] = Accounts.list_users()
end
...
...
just run this specific test set as
mix test test/videologue/accounts_test.exs
-
add tests for
authenticate_by_username_and_password/2withsetupblock usinguser_fixturepre-set for password -
while adding tests for Category in my version, I noticed I haven't added
changesetflow forcreate_categories!/1which allows nullable names; so fixed that
- one of the features provided by
DataCaseisEcto Sandbox; its role is to do DB transaction rollbacks
it just wraps each test in a transaction, then rollbacks.. enabling concurrent testing with same DB
needing
aync: truetag
test the route via endpoint, as a real web request does making sure Controller returns success/redirect/error-codes as desired
- checkig PageController shows
use VideologueWeb.ConnCasethat adds support of conn_case.ex
if using PostgreSQL; even here
ConnCasecan be passedasync: true; not with all DBs
uses
Phoenix.ConnTestto set up API, import convenient aliasesensure to be tested Endpoint is configured
setuphere returnconnif:okassertion helpers like
html_response/2,json_response/2are availableadd
import Videologue.TestHelperstousingmacro inConnCase; making fixture functions available in controller tests
- add following for non-auth causing redirects, and run Mix tests by line-number on this script to just check this
describe "logged-out user" do
test "gets redirected for all video actions", %{conn: conn} do
[
get(conn, Routes.video_path(conn, :new)),
get(conn, Routes.video_path(conn, :index)),
get(conn, Routes.video_path(conn, :show, "101")),
get(conn, Routes.video_path(conn, :edit, "101")),
get(conn, Routes.video_path(conn, :update, "101", %{})),
get(conn, Routes.video_path(conn, :create, %{})),
get(conn, Routes.video_path(conn, :delete, "101")),
] |> Enum.each(fn conn ->
assert html_response(conn, 302)
assert conn.halted
end)
end
end
- don't embed
user_idis session forAuthplug to be tricked by, as that could cause leaky implementationdirect request to session controller everytime would be expensive
- test login mechanism in isolation; build a bypass for rest usecases
add following pat-match for
callin auth.ex to ensure if acurrent_userexists it's honored
def call(conn, _opts) when not is_nil(conn.assigns.current_user), do: conn
now tests for logged-in users are much cleaner
- adding
setup %{conn: conn, login_as: username}, do: login(conn, username)like prep functions to make session have user-id for relevant video
-
now to provide
login_as: usernameconstruct tosetup; for each test used with it add@tag login_as: "alice" -
tag module attribute accepts keyword-list/atom; providing atom is a way to provide flag style attribs
-
can also be used to filter tests as
mix run test/videologue_web --only login_as -
had to
{:ok, conn} = recycle(conn) |> conn_assign(user)before every later HTTP request in tests; else it lost user-id in Conn Assigns -
need to cover negative flows which have been managed for explicitly; so to ensure they don't break.. like access of other user's content
Ecto.NoResultsErrorgets treated byPlugas404hence test-able viaassert_error_sent
should test authentication code now, as getting bypassed in Integration Test
- AuthTest uses
setuptobypass_through/3asauthenticate_userputs flash &:browserpipeline in router plugsfetch_flashto set it up
our Unit Test depends on other functionality like
fetch_flash; here test-helperbypass_through/3allows to do a request that goes via entire pipeline but bypasses router dispatchperforming
getonbypass_throughaccesses endpoint and stops at browser pipeline; here path provided isn't used by Router just stored in connection
-
now we keep this
setupfor all functions, as without it tests forlogin/logoutwill error forsession not fetched... which gets prepared by ourbypass_through |> get -
adding tests for
callis simple to check if a placed user id in session gets picked into Assigns -
test time can be reduce by tweaking hashing of passwords for tests only
config :pbkdf2_elixir, :rounds, 1toconfig/test.exs
- since Phoenix templates are just functions in Parent's View modules, can test like any other
Part.II Chapter-09 Watching Videos