← docs.speechwave.live

ExUnit testing cheatsheet

Running tests

mix test                                    # all tests
mix test test/speechwave/talks_test.exs     # one file
mix test test/speechwave/talks_test.exs:48  # one test (by line)
mix test --trace                            # verbose (show names)
mix test --failed                           # re-run only failures

Test structure

defmodule MyApp.SomeTest do
  use MyApp.DataCase              # or ConnCase for web tests

  import MyApp.SomeFixtures       # factory functions

  setup do
    thing = thing_fixture()
    %{thing: thing}               # returned map → test context
  end

  describe "function_name/arity" do
    test "description", %{thing: thing} do
      assert thing.field == "value"
    end
  end
end

Assertions

AssertionChecks
assert x == yEquality
assert xTruthy
refute xFalsy
assert {:ok, val} = exprPattern match succeeds, binds val
assert x =~ "sub"String contains / regex match
assert x in listMembership
assert_raise Error, fn -> ... endException raised
assert_receive msg, timeoutMessage in process mailbox
refute_receive msg, timeoutNo such message received

Changeset testing

# errors_on/1 comes from DataCase
assert {:error, cs} = create_thing(%{name: nil})
assert "can't be blank" in errors_on(cs).name

# Checking validity without inserting
cs = Thing.changeset(%Thing{}, %{name: "valid"})
assert cs.valid?

LiveView testing

import Phoenix.LiveViewTest

# Mount
{:ok, view, html} = live(conn, "/path")

# Click
render_click(view, "event_name", %{"key" => "val"})
view |> element("#btn") |> render_click()
view |> element("button", "Button Text") |> render_click()

# Form
view |> form("#form-id", data: %{field: "val"}) |> render_submit()
view |> element("#form-id") |> render_change(%{"data" => %{"field" => "val"}})

# DOM assertions
assert has_element?(view, "#element-id")
assert has_element?(view, "#element-id", "text content")
refute has_element?(view, "#element-id")
assert render(view) =~ "some text"

# Redirect on mount
assert {:error, {:redirect, %{to: path}}} = live(conn, "/path")

PubSub testing

# Subscribe from test process
Phoenix.PubSub.subscribe(MyApp.PubSub, "topic")

# Trigger action
render_click(view, "event", %{})

# Assert broadcast received
assert_receive %Phoenix.Socket.Broadcast{
  event: "event_name",
  payload: %{key: value}
}, 500

# Assert NOT received (e.g., rate limited)
refute_receive %Phoenix.Socket.Broadcast{event: "event_name"}, 200

Base cases

BaseUse forProvides
DataCaseContext / schema testsDB sandbox, Ecto imports, errors_on/1
ConnCaseController / LiveView testsDB sandbox + conn, log_in_user/2
ChannelCaseChannel testsDB sandbox + channel helpers