Python's `assert` statement on its own is minimal: if the expression is falsy, it raises `AssertionError` with no useful information:
```python
# plain Python assert
assert result == expected
# → AssertionError (just the exception, nothing else)
```
pytest solves this with **assertion rewriting**. When pytest imports your test file, it transforms the bytecode so that every `assert` captures both sides of the comparison before evaluating it. On failure, you see exactly what differed:
```
# comparing lists:
AssertionError: assert [1, 2, 3] == [1, 2, 4]
At index 2 diff: 3 != 4
# comparing dicts:
AssertionError: assert {'name': 'Alice', 'age': 31} == {'name': 'Alice', 'age': 30}
Differing items:
{'age': 31} != {'age': 30}
# comparing strings:
AssertionError: assert 'hello earth' == 'hello world'
At position 6 diff: 'e' != 'w'
```
This makes failures self-diagnosing. You see *what* differed, not just *that* something differed.
**`==` vs `is`**
`==` tests *equality* (same value). `is` tests *identity* (the exact same object in memory). Use `is` for booleans and `None`:
```python
assert result is True # result is the boolean True
assert result == True # also works, but 1 == True is also True (less strict)
assert result is not None # clear and idiomatic
```
For numbers, strings, and collections, always use `==`. The `is` check on strings and integers can give unexpected results due to Python's object interning.
**Negation:**
```python
assert x != y # not equal
assert x not in lst # not in collection
assert not condition # general negation
```
**Custom failure messages:**
Add a message after the assertion — pytest shows it alongside the assertion itself:
```python
assert score >= 50, f"Expected score ≥ 50, got {score}"
# → AssertionError: Expected score ≥ 50, got 42
# assert 42 >= 50
```
**Floating-point comparisons:**
`0.1 + 0.2` in Python is not exactly `0.3` due to binary floating-point representation. Use `pytest.approx`:
```python
import pytest
assert 0.1 + 0.2 == pytest.approx(0.3) # default: 1e-6 relative tolerance
assert result == pytest.approx(1.5, rel=1e-3) # within 0.1%
assert result == pytest.approx(0.0, abs=1e-9) # absolute tolerance (better near zero)
```
Use `rel` (relative) when the magnitude is large; use `abs` (absolute) when the expected value is at or near zero (dividing by zero in the relative check would be a problem).
```python
# Equality / inequality
assert x == y
assert x != y
# Ordering
assert x > y
assert x >= y
assert x < y
assert x <= y
# Membership
assert item in collection
assert item not in collection
# Type
assert isinstance(obj, SomeClass) # also matches subclasses
assert type(obj) is int # exact type only
# Truthiness
assert value # truthy (non-zero, non-empty, not None)
assert not value # falsy
# Floats
assert x == pytest.approx(y) # default rel tolerance 1e-6
assert x == pytest.approx(y, rel=1e-3) # 0.1% tolerance
assert x == pytest.approx(y, abs=0.01) # absolute tolerance ±0.01
# Strings
assert s.startswith('prefix')
assert s.endswith('suffix')
assert 'substring' in s
# Custom message shown on failure
assert condition, f"Descriptive message: got {value}"
```
Write tests for `to_celsius(f)` that converts Fahrenheit to Celsius using `(f - 32) * 5 / 9`. Assert the result for at least three values: 32°F (0°C), 212°F (100°C), and 98.6°F (37°C). Use `pytest.approx` for float comparisons.
Implement `circle_area(r)` that returns `π * r²` using `math.pi`. Write tests that verify the area for `r=3` is approximately `28.274` (within 0.1% tolerance) and for `r=1` is approximately `3.14159`. Also test `r=0`.
import math
import pytest
def circle_area(r):
pass # implement here
def test_circle_area():
pass
Write `top_scores(scores, n)` that returns the top `n` scores from a list, sorted in descending order. Write tests asserting the return type is a list, its length equals `n`, and specific values are present or absent.
def top_scores(scores, n):
pass # implement here
def test_top_scores():
pass
Solution
def top_scores(scores, n):
return sorted(scores, reverse=True)[:n]
def test_top_scores_returns_list():
result = top_scores([5, 1, 8, 3, 9], 3)
assert isinstance(result, list)
def test_top_scores_length():
result = top_scores([5, 1, 8, 3, 9], 3)
assert len(result) == 3
def test_top_scores_correct_values():
result = top_scores([5, 1, 8, 3, 9], 3)
assert 9 in result
assert 8 in result
assert 5 in result
assert 1 not in result
Write `parse_user(s)` that parses a string like `'name:Alice,age:30'` into a dict. Write tests asserting specific keys exist, values are correct, and unexpected keys are absent.
def parse_user(s):
result = {}
for pair in s.split(','):
key, value = pair.split(':')
result[key.strip()] = value.strip()
return result
def test_parse_user_name():
user = parse_user('name:Alice,age:30')
assert 'name' in user
assert user['name'] == 'Alice'
def test_parse_user_age():
user = parse_user('name:Alice,age:30')
assert 'age' in user
assert user['age'] == '30'
def test_parse_user_no_extra_keys():
user = parse_user('name:Alice,age:30')
assert 'email' not in user
assert len(user) == 2
Write `format_greeting(name, title)` that returns `'Dear {title}. {name},'`. Write tests asserting the result starts with 'Dear', ends with ',', contains the name, and has no double spaces.
def format_greeting(name, title):
pass # implement here
def test_format_greeting():
pass
Solution
def format_greeting(name, title):
return f'Dear {title}. {name},'
def test_greeting_starts_with_dear():
result = format_greeting('Smith', 'Dr')
assert result.startswith('Dear')
def test_greeting_ends_with_comma():
result = format_greeting('Smith', 'Dr')
assert result.endswith(',')
def test_greeting_contains_name():
result = format_greeting('Smith', 'Dr')
assert 'Smith' in result
def test_greeting_no_double_spaces():
result = format_greeting('Smith', 'Dr')
assert ' ' not in result
No split tab
Cookie preferences
We use necessary cookies to run the site. With your permission, we can also save your site preferences and use analytics and advertising cookies to understand usage and support the project.
Open tools in tabs.Exercises, IDE tools, and trainers stay available as site tabs.
Switch without losing context.Move between explanations, code, and utilities while keeping your place.
Use the sidebar as your map.The left panels hold navigation, settings, files, libraries, and tool controls.
PythonJavaScriptSQLite
One IDE, three practical modes
Python in the browser.Run small scripts, try libraries, and practice API requests without installing anything.
JavaScript for quick experiments.Test browser-friendly code and compare ideas next to your learning materials.
SQLite for data practice.Open the database explorer to inspect tables, write queries, and learn SQL workflows locally.
TopicIDE
Work side by side with split tabs
Keep instructions visible.Open an exercise or reference page beside the IDE instead of jumping back and forth.
Compare tools while you learn.Place regex checks, explanations, and code experiments next to each other when the task needs it.
Close the split when you are done.The workspace returns to a single focused tab, and your open site tabs remain available.
Code Typing Trainer
Or plain text
This trainer is designed for a physical keyboard.Open this section on a laptop or desktop with a wide screen. Touch typing practice will not work correctly on a phone.
Speed: 0 chars/min
0 words/min
Best speed (60s): 0 chars/min
0 words/min
Errors: 0
Total time: 0.0 s
To practice touch typing, avoid looking at your physical keyboard.