Mojo Assertions
An assertion is a statement that declares something must be true at a specific point in your program. If it is not true, the program halts immediately with a clear error message. Assertions act as sanity checks that catch bugs early — during development and testing — before they silently corrupt results in production.
The Security Guard Analogy
Your function = a VIP room
Assertion = the security guard at the door
Without guard:
Anyone enters → chaos inside
With assertion:
Guard checks: "Is x positive?"
If yes → entry allowed
If no → STOP, loud alarm, clear message
Assertions stop broken assumptions before they do damage.
Basic Assertion
from testing import assert_true, assert_false, assert_equal
fn main() raises:
var x = 10
assert_true(x > 0, "x must be positive") # passes silently
assert_true(x > 20, "x must be positive") # FAILS — program halts
print("This line never runs")
When an assertion fails, Mojo raises an Error containing the message you provided. The program stops at that line, giving you the exact location and reason for the failure.
assert_true and assert_false
from testing import assert_true, assert_false
fn validate_score(score: Int) raises:
assert_true(score >= 0, "Score cannot be negative")
assert_true(score <= 100, "Score cannot exceed 100")
assert_false(score == 0 and score == 100,
"Score cannot be both 0 and 100")
fn main() raises:
validate_score(85) # all assertions pass
validate_score(-5) # first assertion fails:
# "Score cannot be negative"
assert_equal and assert_not_equal
from testing import assert_equal, assert_not_equal
fn add(a: Int, b: Int) -> Int:
return a + b
fn main() raises:
assert_equal(add(2, 3), 5, "2 + 3 must equal 5")
assert_equal(add(0, 0), 0, "0 + 0 must equal 0")
assert_not_equal(add(1, 1), 3, "1 + 1 must not equal 3")
print("All assertions passed!")
Assertions as Documentation
Assertions describe the rules your function assumes. They serve as living documentation that runs and checks itself every time the code executes.
fn compute_discount(price: Float64, discount_pct: Float64) -> Float64 raises:
# These assertions document the rules for valid input
assert_true(price >= 0.0, "Price must be non-negative")
assert_true(discount_pct >= 0.0, "Discount cannot be negative")
assert_true(discount_pct <= 100.0, "Discount cannot exceed 100%")
return price * (1.0 - discount_pct / 100.0)
fn main() raises:
print(compute_discount(200.0, 25.0)) # 150.0
print(compute_discount(100.0, 110.0)) # FAILS: Discount cannot exceed 100%
Assertion flow:
compute_discount(100.0, 110.0)
│
├── price >= 0? 100 >= 0? True → pass
├── discount >= 0? 110 >= 0? True → pass
└── discount <= 100? 110 <= 100? False → FAIL
"Discount cannot exceed 100%"
Compile-Time Assertions with constrained()
For compile-time parameters, use constrained() to enforce rules that are checked before the program runs. If a compile-time parameter violates the constraint, the compiler rejects the code with a clear message.
from builtin.constrained import constrained
fn process[width: Int]():
constrained[width > 0, "width must be positive"]()
constrained[width % 2 == 0, "width must be even"]()
print("Processing with width:", width)
fn main():
process[8]() # passes both constraints
process[0]() # compile error: "width must be positive"
process[3]() # compile error: "width must be even"
Runtime assertion: checked when the code runs
Compile-time constrained(): checked when the compiler runs
→ zero runtime cost
→ error before any code executes
Writing Unit Tests with Assertions
from testing import assert_equal, assert_true
fn fibonacci(n: Int) -> Int:
if n <= 1:
return n
var a = 0
var b = 1
for _ in range(2, n + 1):
var temp = a + b
a = b
b = temp
return b
fn test_fibonacci() raises:
assert_equal(fibonacci(0), 0, "fib(0) = 0")
assert_equal(fibonacci(1), 1, "fib(1) = 1")
assert_equal(fibonacci(5), 5, "fib(5) = 5")
assert_equal(fibonacci(10), 55, "fib(10) = 55")
assert_true(fibonacci(20) > fibonacci(19), "Fibonacci is increasing")
print("All fibonacci tests passed!")
fn main() raises:
test_fibonacci()
Assertions vs Error Handling
Assertions: Error handling: For bugs in YOUR code For problems from OUTSIDE your code "This SHOULD never happen" "This MIGHT happen in production" Disable in production (optional) Always active Catch logical errors early Handle user input, network, files assert x > 0 ← programming error raise Error(...) ← runtime condition
Key Takeaways
Assertions verify that your assumptions hold at specific points in your code. Use assert_true, assert_false, assert_equal, and assert_not_equal from the testing module. Failed assertions halt the program with the message you specified, identifying the bug location immediately. Use constrained() for compile-time parameter validation at zero runtime cost. Assertions document the rules your code depends on and test them continuously during development. Use them heavily in development and testing; they are distinct from error handling, which covers expected runtime failures.
