ይህ ትምህርት ገና ወደ አማርኛ አልተተረጎመም፤ ስለዚህ በእንግሊዝኛ ቀርቧል። የእንግሊዝኛውን ገጽ ክፈቱ
pytest basics
Plain assert stops at the first failure and doesn't say what went wrong. Python
programmers use a tool that fixes both: it runs every test, then explains each failure
with the values involved. By the end of this lesson you'll write tests in their own
file, run them, and read the report.
Tests in their own file
is that tool. It isn't part of Python: on a computer you install it, like the packages in lesson 8.8. Here it loads the first time you press Run tests.
grades.py is lesson 5.8's grade_for. Next to it, test_grades.py holds three
.
Each imports what it tests (lesson 8.5) and makes one assertion. Press Run tests:
grades.py
def grade_for(score):
if score >= 85:
return "A"
elif score >= 70:
return "B"
elif score >= 50:
return "C"
else:
return "F"In the editor, press Escape then Tab to move on.
test_grades.py
from grades import grade_for
def test_top():
assert grade_for(90) == "A"
def test_boundary():
assert grade_for(85) == "A"
def test_fail():
assert grade_for(49) == "F"In the editor, press Escape then Tab to move on.
The command line shows what ran: pytest -q, "quietly". pytest looked in the folder for
files named test_*.py or *_test.py, and in them for functions whose names start with
test. Name yours test_ and the case, like test_boundary. It ran each one and printed
a dot for each
test, then 3 passed and how long it took (that time changes every run). All your test
functions together are your
.
pytest only runs what fits its naming rules. The file below has one function with a true
assertion, named check_top. Answer, then run it:
ጥያቄ
What will pytest report for a file whose only function is check_top?
test_grades.py
from grades import grade_for
def check_top():
assert grade_for(90) == "A"In the editor, press Escape then Tab to move on.
grades.py
def grade_for(score):
if score >= 85:
return "A"
elif score >= 70:
return "B"
elif score >= 50:
return "C"
else:
return "F"In the editor, press Escape then Tab to move on.
Reading a failure
Here's a bigger suite of six tests, and lesson 5.8's bug: > 85 instead of >= 85.
Plain assert stopped at the first false assertion. Answer, then run it:
ጥያቄ
The bug changes only grade_for(85). What does the last line of pytest's report start with?
grades.py
def grade_for(score):
if score > 85:
return "A"
elif score >= 70:
return "B"
elif score >= 50:
return "C"
else:
return "F"In the editor, press Escape then Tab to move on.
test_grades.py
from grades import grade_for
def test_top():
assert grade_for(90) == "A"
def test_boundary():
assert grade_for(85) == "A"
def test_middle():
assert grade_for(75) == "B"
def test_pass():
assert grade_for(50) == "C"
def test_fail():
assert grade_for(49) == "F"
def test_zero():
assert grade_for(0) == "F"In the editor, press Escape then Tab to move on.
Read the report from the top. .F.... is one character per test, in order: the second
one, test_boundary, is the
one. Under FAILURES, pytest shows that test's code, with > at the line that failed.
Then come the E lines, the explanation:
E AssertionError: assert 'B' == 'A'
E
E - A
E + BThis is the same assertion that gave a bare AssertionError in lesson 9.1, now with
both values: grade_for(85) returned 'B', and the test said 'A'. The - line is the
right side of == and the + line is the left side. Write the call on the left and the
answer you expect on the right, as here, and - is always your answer, + the code's.
Below them, test_grades.py:9 is the file and line. The last two lines sum it up:
FAILED test_grades.py::test_boundary, then the count.
Each test starts fresh
A test file isn't a script that runs top to bottom. pytest calls each test function on its own, as the last two lines here do by hand. Predict:
ውጤቱን ገምቱ
Decide before you look. Guessing wrong is how this sticks.
def test_top():
grade = "A"
assert grade == "A"
def test_same_grade():
assert grade == "A"
test_top()
test_same_grade()Python prints
Traceback (most recent call last):
File "<your code>", line 11, in <module>
test_same_grade()
~~~~~~~~~~~~~~~^^
File "<your code>", line 7, in test_same_grade
assert grade == "A"
^^^^^
NameError: name 'grade' is not definedgrade is a local name of test_top (lesson 5.3): it's gone when that call ends. test_same_grade has no name grade of its own, so Python raises NameError. If you expected the second test to see the first test's grade, you read the file as one script.
pytest does the same, and reports it as a failing test:
test_grades.py
from grades import grade_for
def test_top():
grade = grade_for(90)
assert grade == "A"
def test_same_grade():
assert grade_for(95) == gradeIn the editor, press Escape then Tab to move on.
grades.py
def grade_for(score):
if score >= 85:
return "A"
elif score >= 70:
return "B"
elif score >= 50:
return "C"
else:
return "F"In the editor, press Escape then Tab to move on.
The report says E NameError: name 'grade' is not defined. Give each test
everything it needs: here, assert grade_for(95) == "A".
Comparing floats
Lesson 2.1 showed that 0.1 + 0.2 == 0.3 is False: most floats are a tiny bit off
from the decimal you wrote. pytest.approx compares with a small tolerance instead. It needs import pytest:
import pytest
def test_plain():
assert 0.1 + 0.2 == 0.3
def test_approx():
assert 0.1 + 0.2 == pytest.approx(0.3)In the editor, press Escape then Tab to move on.
Use approx whenever the answer is a float that comes from a calculation.
መልመጃ
Test vat
Here's vat from lesson 5.1, in money.py. Run the starter first: vat(100) should
be 115, and pytest shows what it really returned. Fix that test with pytest.approx,
then add a test for a price of 0.
Your code
test_money.py
from money import vat
def test_vat_250():
assert vat(250) == 287.5
def test_vat_100():
assert vat(100) == 115In the editor, press Escape then Tab to move on.
money.py
def vat(price):
return price * 1.15In the editor, press Escape then Tab to move on.
መፍትሄውን አሳይHide the solution
This is one way to solve it, not the only one. If yours prints the same thing, it works.
import pytest
from money import vat
def test_vat_250():
assert vat(250) == pytest.approx(287.5)
def test_vat_100():
assert vat(100) == pytest.approx(115)
def test_vat_zero():
assert vat(0) == 0ጥያቄ
A folder has grades.py, testing_grades.py, and test_grades.py, each with functions named test_something. Which file does pytest run tests from?
ዋና ዋና ነጥቦች
- pytest runs every function whose name starts with
testin every file namedtest_*.py(or*_test.py), each on its own, and reports how many passed and failed. - A function or file with another name is never run, and a test that never ran isn't a pass: check the count.
- Read a failure's
Elines:assert 'B' == 'A'shows both sides;-is the right side of==,+the left. Put the call on the left, the answer on the right. - Each test starts fresh. Use
pytest.approxfor floats.