Elixir basics · Lesson 24 (open contents)
Test behavior and boundaries
Use setup data, doctests, focused assertions, and async-safe tests.
Run this first
Run it once, change one input, and compare the new result.
# lib/score.ex
defmodule Score do
def pass?(score) when is_integer(score) and score in 60..100, do: true
def pass?(_score), do: false
def check(score) when is_integer(score) and score in 0..100,
do: {:ok, score}
def check(_score), do: {:error, :out_of_range}
end
# test/score_test.exs
defmodule ScoreTest do
use ExUnit.Case, async: true
test "pass boundary" do
assert Score.pass?(60)
refute Score.pass?(59)
end
endmix testreports one passing test containing two boundary assertions.
Read from the first line down
- Read
use ExUnit.Case, async: true: Allow independent tests to run concurrently. - Read
setup: Return context data for each test. - Read
doctest Module: Run documented IEx examples as tests.
Symbols are not secret signs
use ExUnit.Case, async: trueAllow independent tests to run concurrently.
setupReturn context data for each test.
doctest ModuleRun documented IEx examples as tests.
Match each name to its meaning
test boundary
Boundary cases sit where behavior changes, such as 59 versus 60.
setup
A setup callback prepares fresh data for each test.
doctest
Doctest runs examples written in module documentation.
Why these forms are useful
Run the example first. Predict one result, then change one input and run it again.
Boundary cases sit where behavior changes, such as 59 versus 60.
A setup callback prepares fresh data for each test.
Close the answer and try
Add a test that rejects a negative score.
test "negative score" do
assert Score.check(-1) == ____
endTarget result: Expect {:error, :out_of_range}.
Stuck? Read one hint
Use the tagged error returned by the public API.
After you run it, see one answer
test "negative score" do
assert Score.check(-1) == {:error, :out_of_range}
endThink about it: When is `async: true` unsafe?
Avoid it when tests share mutable external state such as one database record or global process.
Remember these three lines
- 1
Test behavior, not private steps.
- 2
Place tests on both sides of boundaries.
- 3
Share examples through setup or doctests only when they stay clear.