使用 ExUnit 进行单元测试
使用内置的 ExUnit 框架,为 Elixir 模块和函数编写快速可靠的单元测试。
使用 ExUnit 进行单元测试 是 CoddyKit 上的免费 Elixir & Phoenix: Scalable Backend Development 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Elixir & Phoenix: Scalable Backend Development 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Elixir & Phoenix: Scalable Backend Development 课程共包含 4 节课。
本课时的部分内容尚未翻译,以英文显示。
Intro to ExUnit
Welcome to unit testing with ExUnit! ExUnit is Elixir's built-in testing framework, designed to help you write reliable and maintainable code.
Unit tests focus on small, isolated parts of your code, like individual functions or modules. They ensure each component works as expected, giving you confidence as your application grows.
Your First ExUnit Test
Elixir test files typically end with _test.exs and are placed in a test/ directory. Inside, you use ExUnit.Case to bring in testing functionalities.
A test block starts with test "description" do ... end. Here's a simple example:
defmodule MyMath do
def add(a, b), do: a + b
end
defmodule MyMathTest do
use ExUnit.Case, async: true
test "adds two numbers correctly" do
assert MyMath.add(1, 2) == 3
end
endAsserting with `assert`
The most common assertion in ExUnit is assert. It checks if an expression evaluates to a truthy value (anything other than false or nil).
You often use it to compare expected outcomes with actual results.
defmodule Calculator do
def multiply(a, b), do: a * b
end
defmodule CalculatorTest do
use ExUnit.Case, async: true
test "multiplies positive numbers" do
assert Calculator.multiply(2, 3) == 6
end
test "multiplies by zero" do
assert Calculator.multiply(5, 0) == 0
end
endRefuting with `refute`
Sometimes, you want to ensure something is not true. That's where refute comes in. It's the opposite of assert.
refute passes if its argument evaluates to a falsy value (false or nil).
defmodule Validator do
def is_negative(num), do: num < 0
end
defmodule ValidatorTest do
use ExUnit.Case, async: true
test "refutes positive numbers as negative" do
refute Validator.is_negative(10)
refute Validator.is_negative(0)
end
test "asserts negative numbers" do
assert Validator.is_negative(-5)
end
endTesting for Exceptions
What if your function is supposed to raise an error under specific conditions? assert_raise lets you test for that!
You provide the expected exception type and an optional message, along with a function that should trigger the error.
defmodule Divider do
def divide(a, b) do
if b == 0, do: raise(ArgumentError, "Cannot divide by zero"), else: a / b
end
end
defmodule DividerTest do
use ExUnit.Case, async: true
test "raises ArgumentError for division by zero" do
assert_raise ArgumentError, "Cannot divide by zero", fn ->
Divider.divide(10, 0)
end
end
endSetting Up Test Context
Many tests need common setup, like creating a temporary resource or a mock user. ExUnit's setup callback runs before each test in a module.
It should return {:ok, assigns} where assigns is a keyword list or map that will be available in your test function's arguments.
defmodule UserProfileTest do
use ExUnit.Case, async: true
setup do
# This runs before each test
user = %{id: 101, name: "Jane Doe", email: "jane@example.com"}
{:ok, user: user, admin: true}
end
test "user has a name", %{user: user} do
assert user.name == "Jane Doe"
end
test "context includes admin flag", %{admin: admin_status} do
assert admin_status == true
end
endGrouping Tests with `describe`
As your test files grow, you might want to logically group related tests. The describe macro helps organize tests within a module, making your test suite more readable.
You can even nest describe blocks!
defmodule StringUtils do
def capitalize(str), do: String.capitalize(str)
def reverse(str), do: String.reverse(str)
end
defmodule StringUtilsTest do
use ExUnit.Case, async: true
describe "capitalize/1" do
test "capitalizes first letter" do
assert StringUtils.capitalize("hello") == "Hello"
end
test "handles empty string" do
assert StringUtils.capitalize("") == ""
end
end
describe "reverse/1" do
test "reverses a string" do
assert StringUtils.reverse("world") == "dlrow"
end
end
endExecuting Your Tests
Once you've written your tests, running them is simple using Elixir's build tool, Mix.
- To run all tests in your project:
mix test - To run tests in a specific file:
mix test test/my_module_test.exs - To run a specific test by line number:
mix test test/my_module_test.exs:10 - To run tests matching a description:
mix test --only "adds two numbers"
ExUnit Challenge
Consider the following Elixir module designed to check if a number is odd. Which ExUnit assertion correctly tests if NumberChecker.is_odd(5) returns true?
defmodule NumberChecker do
def is_odd(n) when is_integer(n) do
rem(n, 2) != 0
end
endUnit Testing Summary
Great job! You've covered the fundamentals of unit testing with ExUnit.
- ExUnit is Elixir's built-in testing framework.
- Tests are defined in
_test.exsfiles usinguse ExUnit.Case. assertchecks for truthy values,refutefor falsy values.assert_raiseverifies that specific exceptions are thrown.setupcallbacks prepare context for your tests.describeblocks help organize related tests.- You run tests using
mix test.
These skills are crucial for building robust and reliable Elixir applications!
常见问题解答
「使用 ExUnit 进行单元测试」课时是免费的吗?
是的 — 「使用 ExUnit 进行单元测试」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Elixir & Phoenix: Scalable Backend Development 课程的其余内容,请升级到 CoddyKit PRO。 Elixir & Phoenix: Scalable Backend Development 课程共包含 4 节课。
「使用 ExUnit 进行单元测试」这节课中我会学到什么?
使用内置的 ExUnit 框架,为 Elixir 模块和函数编写快速可靠的单元测试。 你通过在浏览器中直接运行的动手代码来练习 Elixir & Phoenix: Scalable Backend Development,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Elixir & Phoenix: Scalable Backend Development 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Elixir & Phoenix: Scalable Backend Development 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「使用 ExUnit 进行单元测试」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Elixir & Phoenix: Scalable Backend Development 课中编写并运行代码吗?
能。每节 Elixir & Phoenix: Scalable Backend Development 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 使用 ExUnit 进行单元测试
- Phoenix 应用集成测试
- 模拟、存根与测试数据
- 使用 StreamData 进行基于属性的测试