ЁЯТ╕ рдзрдбрд╛ 01 тАФ Test рдХрд╛ рдХрд░рд╛рдпрдЪреЗ: рдЙрд╢рд┐рд░рд╛ рд╕рд╛рдкрдбрд▓реЗрд▓реНрдпрд╛ bug рдЪреА рдХрд┐рдВрдордд
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 01 ┬╖ рдкреБрдвреЗ: lesson-02-unit-tests
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рд╣рд╛ рд╕рдВрдкреВрд░реНрдг рдХреЛрд░реНрд╕ рдПрдХрд╛рдЪ рдХрд▓реНрдкрдиреЗрд╡рд░ рдЖрд╣реЗ: code рдореНрд╣рдгрдЬреЗ рдкрд░реАрдХреНрд╖реЗрд▓рд╛ рдмрд╕рд▓реЗрд▓реА рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА, рдЖрдгрд┐ test рдореНрд╣рдгрдЬреЗ рдкрд░реАрдХреНрд╖реЗрддрд▓рд╛ рдкреНрд░рд╢реНрди, рдЬреНрдпрд╛рдЪреЗ рдмрд░реЛрдмрд░ рдЙрддреНрддрд░ рдЖрдзреАрдЪ рдорд╛рд╣реАрдд рдЕрд╕рддреЗ. рджреАрдкрд┐рдХрд╛рдиреЗ рд╢рд╛рд│реЗрдЪрд╛ grading code рд▓рд┐рд╣рд┐рд▓рд╛. рдореБрдЦреНрдп рдкрд░реАрдХреНрд╖рдХ рдХрддрд░рд┐рдирд╛рд▓рд╛ 1200 report cards рдЫрд╛рдкрдгреНрдпрд╛рдЪреНрдпрд╛ рдЖрдзреА рдХрд│рд╛рдпрд▓рд╛ рд╣рд╡реЗ рдХреА рддреЛ рдмрд░реЛрдмрд░ рдЖрд╣реЗ рдХрд╛. рд╕рдВрдкреВрд░реНрдг рдХреЛрд░реНрд╕рдордзреНрдпреЗ рддреБрдореНрд╣реА рд╡рд╛рдкрд░рдгрд╛рд░ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рдЦрд▒реНрдпрд╛ files:
- exam/grades.py тАФ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА: рд╢рд╛рд│реЗрдЪреЗ grading module (grades, rounding, report cards, рдПрдХ attendance client, рдПрдХ рдЫреЛрдЯрд╛ SQLite store)
- exam/lab.py тАФ рдкрд░реАрдХреНрд╖рд╛ рд╣реЙрд▓рдЪреА рд╕рд╛рдзрдиреЗ, рдЫреЛрдЯреНрдпрд╛ deterministic models рдЪреНрдпрд╛ рд░реВрдкрд╛рдд (рдПрдХ рдЫреЛрдЯрд╛ runner, builders, рдмрджрд▓реА рдкрд░реАрдХреНрд╖рдХ, рдПрдХ contract checker, рдПрдХ property tester, coverage, mutants, flaky tests)
- exam/demo.py тАФ рдкреНрд░рддреНрдпреЗрдХ рдзрдбрд╛ рдПрдХ рдЫреЛрдЯрд╛ program рдореНрд╣рдгреВрди (
python3 exam/demo.py <section>; sections:why unit design fixtures doubles integration contract pyramid property mutation flaky ci) - exam/test_exam.py тАФ рдХреЛрд░реНрд╕рдЪреЗ рд╕реНрд╡рддрдГрдЪреЗ 12 checks
- demo-output.txt тАФ рдирд┐рд░реЛрдЧреА run рдХрд╛рдп рдЫрд╛рдкрддреЗ
ЁЯОТ рд╕реБрд░реВ рдХрд░рдгреНрдпрд╛рдкреВрд░реНрд╡реА: рддреБрдореНрд╣рд╛рд▓рд╛ рдлрдХреНрдд Python 3 рд▓рд╛рдЧреЗрд▓, рдмрд╛рдХреА рдХрд╛рд╣реА рдирд╛рд╣реА тАФ рдирд╛
pip install, рдирд╛ network.lab.pyрдордзреНрдпреЗ рд╢рд┐рдХрд╡рдгреНрдпрд╛рд╕рд╛рдареАрдЪреЗ models рдЖрд╣реЗрдд, рдЦрд░реА рд╕рд╛рдзрдиреЗ рдирд╛рд╣реАрдд. Randomness рд▓рд╛ seed рджрд┐рд▓реЗрд▓рд╛ рдЖрд╣реЗ, рдореНрд╣рдгреВрди рдкреНрд░рддреНрдпреЗрдХ run рддреАрдЪ рдЧреЛрд╖реНрдЯ рдЫрд╛рдкрддреЗ. рдЦрд░реА рд╕рд╛рдзрдиреЗ рдореНрд╣рдгрдЬреЗ pytest, Hypothesis, Pact, Playwright, coverage.py рдЖрдгрд┐ mutmut; рдкреНрд░рддреНрдпреЗрдХ рдзрдбрд╛ рддреА рдЦрд▒реНрдпрд╛ project рд╡рд░ рдЕрд╢рд╛ рдЦреБрдгреЗрдЪреНрдпрд╛ blocks рдордзреНрдпреЗ рджрд╛рдЦрд╡рддреЛ, рдЬреНрдпрд╛рдВрдирд╛pip installрд▓рд╛рдЧрддреЗ рдЖрдгрд┐ рдЬреЗ "рдХрд░реВрди рдкрд╛рд╣рд╛" рдЪрд╛ рднрд╛рдЧ рдирд╛рд╣реАрдд.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рд╢рд╛рд│реЗрдЪрд╛ рдирд┐рдпрдо рд╕реЛрдкрд╛ рдЖрд╣реЗ: рддреБрдордЪреА рдЯрдХреНрдХреЗрд╡рд╛рд░реА рдкреВрд░реНрдг рд╕рдВрдЦреНрдпреЗрдд round рдХреЗрд▓реА рдЬрд╛рддреЗ, рдЕрд░реНрдзрд╛ рд╡рд░ рдЬрд╛рддреЛ, рдЖрдгрд┐ 35 рдореНрд╣рдгрдЬреЗ pass.
рджреАрдкрд┐рдХрд╛ code рд▓рд┐рд╣рд┐рддреЗ. рдХрддрд░рд┐рдирд╛ рддреНрдпрд╛рд▓рд╛ рдкрд╛рдЪ рд╕реЛрдкреЗ рдкрд░реАрдХреНрд╖реЗрдЪреЗ рдкреНрд░рд╢реНрди рд╡рд┐рдЪрд╛рд░рддреЗ: 90? A. 65? B. 50? C. 40? D. 10? F. рдкрд╛рдЪ рдкреИрдХреА рдкрд╛рдЪ. ЁЯОЙ
рдордЧ рд╕рдВрдкреВрд░реНрдг рд╢рд╛рд│рд╛ 200 рдЧреБрдгрд╛рдВрдЪрд╛ рдкреЗрдкрд░ рджреЗрддреЗ. 69 рдЧреБрдг рдорд┐рд│рд╛рд▓реЗрд▓реНрдпрд╛ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреАрд▓рд╛ 34.5% рдорд┐рд│рддрд╛рдд. рдирд┐рдпрдо рд╕рд╛рдВрдЧрддреЛ 34.5 тЖТ 35 тЖТ pass. рджреАрдкрд┐рдХрд╛рдЪрд╛ code рдореНрд╣рдгрддреЛ F. тЭМ
рдХрд╛? Python рдЪреЗ round() рдЕрд░реНрдзреНрдпрд╛рд▓рд╛ рд╡рд░ round рдХрд░рдд рдирд╛рд╣реА. рддреЗ рдЕрд░реНрдзреНрдпрд╛рд▓рд╛ рдЬрд╡рд│рдЪреНрдпрд╛ рд╕рдо
рд╕рдВрдЦреНрдпреЗрдХрдбреЗ рдиреЗрддреЗ: round(34.5) рдореНрд╣рдгрдЬреЗ 34. рд╕реЛрдкреНрдпрд╛ рдкреНрд░рд╢реНрдирд╛рдВрдиреА рдХрдзреА рдЕрд░реНрдзреНрдпрд╛рдмрджреНрджрд▓ рд╡рд┐рдЪрд╛рд░рд▓реЗрдЪ рдирд╛рд╣реА.
рдЬрд░ рдХрддрд░рд┐рдирд╛рд▓рд╛ рд╣реЗ рджреАрдкрд┐рдХрд╛рдЪреНрдпрд╛ рдбреЗрд╕реНрдХрд╡рд░рдЪ рдЖрдгрдЦреА рдПрдХрд╛ рдкреНрд░рд╢реНрдирд╛рдиреЗ рд╕рд╛рдкрдбрд▓реЗ, рддрд░ рджреБрд░реБрд╕реНрддреА рдПрдХрд╛ рдУрд│реАрдЪреА рдЖрд╣реЗ. рдкрдг report cards рдкрд╛рдард╡рд▓реЗ рдЬрд╛рдИрдкрд░реНрдпрдВрдд рдХреЛрдгрд╛рд▓рд╛рдЪ рд╕рд╛рдкрдбрд▓реЗ рдирд╛рд╣реА, рддрд░ рддреНрдпрд╛рдЪреА рдХрд┐рдВрдордд 15 рдкреБрдирд░реНрдЫрдкрд╛рдИ, рдирд╛рдкрд╛рд╕ рд╕рд╛рдВрдЧрд┐рддрд▓реЗрд▓реНрдпрд╛ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреАрдВрдирд╛ 5 рдорд╛рдлреАрдкрддреНрд░реЗ, рдЖрдгрд┐ рдПрдХ meeting. Bug рддреЛрдЪ. рдлрд░рдХ рдлрдХреНрдд рдПрдХрдЪ тАФ рддреЛ рдХрдзреА рд╕рд╛рдкрдбрд▓рд╛.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
code["тЬНя╕П Dipika writes grade_v1<br/>round() sends halves to EVEN"]
easy["ЁЯУЭ 5 easy questions<br/>90 65 50 40 10: 5/5 pass"]
desk["ЁЯФН found at the desk<br/>1 failing check, 0 pupils hurt"]
late["ЁЯУм found after posting<br/>15 wrong cards, 5 told they failed"]
code --> easy
easy -->|"one question at 34.5"| desk
easy -->|"no such question"| late
ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/testing/lesson-diagrams.html#l01
тЭУ рдХрд╛рдп
- Test тАФ рдЕрд╕рд╛ code рдЬреЛ рджреБрд╕рд░рд╛ code рдирд┐рд╡рдбрд▓реЗрд▓реНрдпрд╛ input рдиреЗ рдЪрд╛рд▓рд╡рддреЛ рдЖрдгрд┐ рдирд┐рдХрд╛рд▓ рдЕрдкреЗрдХреНрд╖рд┐рдд рдЙрддреНрддрд░рд╛рд╢реА рддрдкрд╛рд╕рддреЛ. рдЙрддреНрддрд░рд╕реВрдЪреА рдЬреЛрдбрд▓реЗрд▓рд╛ рдкрд░реАрдХреНрд╖реЗрдЪрд╛ рдкреНрд░рд╢реНрди.
- Bug (defect) тАФ code рдЬреЗ рдХрд░рд╛рдпрд▓рд╛ рд╣рд╡реЗ рддреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рд╡реЗрдЧрд│реЗ рдХрд░рддреЛ. рдЗрдереЗ: 34.5 рд▓рд╛ D рдРрд╡рдЬреА F рдорд┐рд│рддреЛ.
- Specification тАФ "рдХрд░рд╛рдпрд▓рд╛ рд╣рд╡реЗ" рдореНрд╣рдгрдЬреЗ рдХрд╛рдп. Test рддреНрдпрд╛рдЪреНрдпрд╛ рдЕрдкреЗрдХреНрд╖рд┐рдд рдЙрддреНрддрд░рд╛рдЗрддрдХрд╛рдЪ рдмрд░реЛрдмрд░ рдЕрд╕рддреЛ; рдЗрдереЗ "рдЕрд░реНрдзрд╛ рд╡рд░ round рд╣реЛрддреЛ" рд╣рд╛ рд╢рд╛рд│реЗрдЪрд╛ рдирд┐рдпрдо рдореНрд╣рдгрдЬреЗ spec.
- Test рдХрд╛рдп рд╕рд┐рджреНрдз рдХрд░рддреЛ тАФ рдХреА code рдиреЗ рддреНрдпрд╛ input рд╕рд╛рдареА, рддреНрдпрд╛ рджрд┐рд╡рд╢реА, рддреНрдпрд╛ setup рдордзреНрдпреЗ рдмрд░реЛрдмрд░ рдЙрддреНрддрд░ рджрд┐рд▓реЗ. рддреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдХрд╛рд╣реА рдирд╛рд╣реА.
- Test рдХрд╛рдп рд╕рд┐рджреНрдз рдХрд░реВ рд╢рдХрдд рдирд╛рд╣реА тАФ рдХреА рдПрдХрд╣реА bug рдирд╛рд╣реА. Edsger Dijkstra рдиреЗ рд╣реЗ рдЕрд╕реЗ
рдорд╛рдВрдбрд▓реЗ (1970): testing bugs рдЕрд╕рд▓реНрдпрд╛рдЪреЗ рджрд╛рдЦрд╡реВ рд╢рдХрддреЗ, рдирд╕рд▓реНрдпрд╛рдЪреЗ рдХрдзреАрдЪ рдирд╛рд╣реА.
grade_v15 рдкреИрдХреА 5 pass рдЭрд╛рд▓реЗ рдЖрдгрд┐ рддрд░реАрд╣реА 3 scores рдЪреБрдХреАрдЪреЗ рд╣реЛрддреЗ. - рдЙрд╢рд┐рд░рд╛ рд╕рд╛рдкрдбрд▓реЗрд▓реНрдпрд╛ bug рдЪреА рдХрд┐рдВрдордд тАФ рдЬрд┐рддрдХреНрдпрд╛ рдЙрд╢рд┐рд░рд╛ bug рд╕рд╛рдкрдбрддреЛ рддрд┐рддрдХреА рдЬрд╛рд╕реНрдд рдорд╛рдгрд╕реЗ рдЖрдгрд┐ рдЬрд╛рд╕реНрдд рдХрд╛рдо рддреНрдпрд╛рд▓рд╛ рд▓рд╛рдЧрддреЗ: рддреНрдпрд╛рд╡рд░ рдмрд╛рдВрдзрд▓реЗрд▓рд╛ рдЬрд╛рд╕реНрдд code, рд▓рд┐рд╣рд┐рд▓реЗрд▓рд╛ рдЬрд╛рд╕реНрдд data, рдЪреБрдХреАрдЪреЗ рдЙрддреНрддрд░ рдкрд╛рд╣рд┐рд▓реЗрд▓реА рдЬрд╛рд╕реНрдд рдорд╛рдгрд╕реЗ. рдкреБрд╕реНрддрдХрд╛рдВрдд рдЕрдиреЗрдХрджрд╛ "design рдордзреНрдпреЗ 1├Ч, production рдордзреНрдпреЗ 100├Ч" рдЕрд╢реА рдЧреБрдгреЛрддреНрддрд░реЗ рджрд┐рд▓реА рдЬрд╛рддрд╛рдд. рддреНрдпрд╛рдВрдирд╛ рджрдВрддрдХрдерд╛ рд╕рдордЬрд╛: рдореВрд│ data рддреБрдЯрдкреБрдВрдЬрд╛ рдЖрдгрд┐ рд╡рд╛рджрдЧреНрд░рд╕реНрдд рдЖрд╣реЗ (Laurent Bossavit рдЪреЗ The Leprechauns of Software Engineering рддреНрдпрд╛рдВрдЪрд╛ рдорд╛рдЧ рдХрд╛рдврддреЗ). рджрд┐рд╢рд╛ рдЦрд░реА рдЖрд╣реЗ; рдиреЗрдордХреЗ рдЖрдХрдбреЗ рд╣рд╛ рдирд┐рдпрдо рдирд╛рд╣реА.
- Regression тАФ рдЖрдзреА рдЪрд╛рд▓рдгрд╛рд░реА рдЧреЛрд╖реНрдЯ рдПрдЦрд╛рджреНрдпрд╛ рдмрджрд▓рд╛рдирдВрддрд░ рдореЛрдбрддреЗ. Repo рдордзреНрдпреЗ рд░рд╛рд╣рдгрд╛рд░рд╛ test рддреНрдпрд╛рдирдВрддрд░ рдХрд╛рдпрдо рддреНрдпрд╛рдкрд╛рд╕реВрди рд░рдХреНрд╖рдг рдХрд░рддреЛ.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг рджреБрд╕рд░рд╛ рдкрд░реНрдпрд╛рдп рдореНрд╣рдгрдЬреЗ software рд╡рд╛рдкрд░рдгрд╛рд▒реНрдпрд╛ рд▓реЛрдХрд╛рдВрдХрдбреВрди bugs рд╕рд╛рдкрдбрдгреЗ. рдпрд╛ рдХреЛрд░реНрд╕рдордзрд▓рд╛ рдкреНрд░рддреНрдпреЗрдХ
test рд╣рд╛ рд▓рд╡рдХрд░ рд╡рд┐рдЪрд╛рд░рд▓реЗрд▓рд╛ рдкреНрд░рд╢реНрди рдЖрд╣реЗ тАФ machine рдХрдбреВрди, рдХрд╛рд╣реА рд╕реЗрдХрдВрджрд╛рдВрдд, рдкреНрд░рддреНрдпреЗрдХ рд╡реЗрд│реА рдЬреЗрд╡реНрд╣рд╛
рдХреЛрдгреА code рдмрджрд▓рддреЛ. Tests рдореБрд│реЗ рддреБрдореНрд╣реА рди рдШрд╛рдмрд░рддрд╛ code рдмрджрд▓реВ рд╢рдХрддрд╛: рджреАрдкрд┐рдХрд╛ rounding
рджреБрд░реБрд╕реНрдд рдХрд░рддреЗ рддреЗрд╡реНрд╣рд╛ 12 checks рддрд┐рд▓рд╛ рдПрдХрд╛ рд╕реЗрдХрдВрджрд╛рдд рд╕рд╛рдВрдЧрддрд╛рдд рдХреА рдмрд╛рдХреА рдХрд╛рд╣реА рдореЛрдбрд▓реЗ рдирд╛рд╣реА. рдЖрдгрд┐ test рдореНрд╣рдгрдЬреЗ
рдЪрд╛рд▓рд╡рддрд╛ рдпреЗрдгрд╛рд░реЗ documentation: grade(34.5) == "D" рд╣рд╛ рдирд┐рдпрдо comment рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рд╕реНрдкрд╖реНрдЯ рд╕рд╛рдВрдЧрддреЗ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
exam/grades.py рдордзрд▓реЗ grade_v1(score) Python рдЪреЗ round() рд╡рд╛рдкрд░рддреЗ.
grade(score) рд╣реЗ round_half_up() рд╡рд╛рдкрд░рддреЗ, рдЬреЗ Decimal(str(score)) рдЖрдгрд┐
ROUND_HALF_UP рдиреЗ round рдХрд░рддреЗ. exam/demo.py рдордзрд▓реЗ why() grade_v1 рд▓рд╛ рдкрд╛рдЪ рд╕реЛрдкреЗ
рдкреНрд░рд╢реНрди рд╡рд┐рдЪрд╛рд░рддреЗ, рдордЧ 200 рдЧреБрдгрд╛рдВрдЪреНрдпрд╛ рдкреЗрдкрд░рд╡рд░ 1200 рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреАрдВрдЪреНрдпрд╛ seeded рд╢рд╛рд│реЗрдЪреЗ grading рдХрд░рддреЗ (рдореНрд╣рдгреВрди рдкреНрд░рддреНрдпреЗрдХ
score рдкреВрд░реНрдг рдХрд┐рдВрд╡рд╛ рдЕрд░реНрдзрд╛ рдЕрд╕рддреЛ) рдЖрдгрд┐ рджреБрд░реБрд╕реНрдд grade() рдкреЗрдХреНрд╖рд╛ рдХрд┐рддреА cards рд╡реЗрдЧрд│реЗ рдпреЗрддрд╛рдд рддреЗ рдореЛрдЬрддреЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 exam/demo.py why
python3 - <<'EOF'
from exam.grades import grade, grade_v1
print("round() on halves:", [round(x) for x in (0.5, 1.5, 2.5, 34.5, 35.5, 74.5)])
for out_of in (100, 200, 40, 80):
scores = [m * 100 / out_of for m in range(out_of + 1)]
wrong = [s for s in scores if grade_v1(s) != grade(s)]
print(f"paper out of {out_of:>3}: {len(scores):>3} possible scores ┬╖ v1 wrong at {wrong}")
EOF
python3 exam/test_exam.py
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
why рдЫрд╛рдкрддреЗ:
тФАтФА Dipika's grade_v1 sits 5 easy exam questions: 5/5 correct тАФ and it still has a bug
the whole school sits a paper out of 200 (1200 students): 15 report cards get the wrong grade
wrong scores: [34.5, 44.5, 74.5] ┬╖ 5 students told they FAILED at 34.5
рддреБрдордЪрд╛ snippet рдЫрд╛рдкрддреЛ:
round() on halves: [0, 2, 2, 34, 36, 74]
paper out of 100: 101 possible scores ┬╖ v1 wrong at []
paper out of 200: 201 possible scores ┬╖ v1 wrong at [34.5, 44.5, 74.5]
paper out of 40: 41 possible scores ┬╖ v1 wrong at []
paper out of 80: 81 possible scores ┬╖ v1 wrong at []
Checks рд╢реЗрд╡рдЯреА 12/12 passed рдЫрд╛рдкрддрд╛рдд.
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
рддреЛрдЪ code 100, 40 рдХрд┐рдВрд╡рд╛ 80 рдЧреБрдгрд╛рдВрдЪреНрдпрд╛ рдкреЗрдкрд░рд╕рд╛рдареА рдЕрдЪреВрдХ рдЖрд╣реЗ, рдЖрдгрд┐ 200 рдЧреБрдгрд╛рдВрдЪреНрдпрд╛ рдкреЗрдкрд░рд╕рд╛рдареА рдЪреБрдХреАрдЪрд╛ рдЖрд╣реЗ. рдлрдХреНрдд рдкреВрд░реНрдг рд╕рдВрдЦреНрдпреЗрддрд▓реЗ scores рд╡рд╛рдкрд░рдгрд╛рд░рд╛ test suite рдХрд╛рдпрдо pass рд╣реЛрдд рд░рд╛рд╣рд┐рд▓рд╛ рдЕрд╕рддрд╛. Bug 201 рдкреИрдХреА рдиреЗрдордХреНрдпрд╛ рддреАрди inputs рд╡рд░ рд░рд╛рд╣рддреЛ тАФ 34.5, 44.5 рдЖрдгрд┐ 74.5, рдореНрд╣рдгрдЬреЗ grade рд░реЗрд╖реЗрдЪреНрдпрд╛ рдЕрдЧрджреА рдЦрд╛рд▓рдЪреЗ рдЕрд╕реЗ рдЕрд░реНрдзреЗ, рдЬреНрдпрд╛рдВрдЪрд╛ рд╕рдо рд╢реЗрдЬрд╛рд░реА рдЦрд╛рд▓реА рдЖрд╣реЗ (59.5 рд╣реЗ 60 рд╡рд░ round рд╣реЛрддреЗ, рдЬреЛ рд╕рдо рдЖрд╣реЗ, рдореНрд╣рдгреВрди рддреЗ рдпреЛрдЧрд╛рдпреЛрдЧрд╛рдиреЗ рдмрд░реЛрдмрд░ рдпреЗрддреЗ). рддреЗ рддреАрди рд╢реЛрдзрдгреЗ рд╣рд╛рдЪ рдзрдбрд╛ 03 рдЪрд╛ рд╡рд┐рд╖рдп рдЖрд╣реЗ.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- рдлрдХреНрдд рд╕реЛрдкреЗ, рдиреЗрд╣рдореАрдЪреЗ inputs test рдХрд░рдгреЗ тАФ "happy path"
- "рд╕рдЧрд│реЗ tests pass" рдореНрд╣рдгрдЬреЗ "рдПрдХрд╣реА bug рдирд╛рд╣реА" рдЕрд╕реЗ рд╕рдордЬрдгреЗ
- code рдЪрд╛рд▓рд╡реВрди рддреНрдпрд╛рдиреЗ рдЬреЗ рдЫрд╛рдкрд▓реЗ рддреЗ copy рдХрд░реВрди рдЕрдкреЗрдХреНрд╖рд┐рдд рдЙрддреНрддрд░ рд▓рд┐рд╣рд┐рдгреЗ (рдордЧ test bug рдЪ рддрдкрд╛рд╕рддреЛ)
- test рди рдХрд░рддрд╛ рднрд╛рд╖реЗрдЪреЗ rounding, dates рдХрд┐рдВрд╡рд╛ floats business рдирд┐рдпрдорд╛рд╢реА рдЬреБрд│рддреАрд▓ рдЕрд╕рд╛ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдареЗрд╡рдгреЗ
- tests repo рдордзреНрдпреЗ рди рдареЗрд╡рддрд╛ laptop рд╡рд░ рдареЗрд╡рдгреЗ, рдЬрд┐рдереЗ рдкреНрд░рддреНрдпреЗрдХ рдмрджрд▓ рддреЗ рдЪрд╛рд▓рд╡рдд рдирд╛рд╣реА
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
рд╣рд╛рдЪ check pytest рдордзреНрдпреЗ, рд╕рд░реНрд╡рд╛рдзрд┐рдХ рд╡рд╛рдкрд░рд▓рд╛ рдЬрд╛рдгрд╛рд░рд╛ Python test runner. рдЦрд▒реНрдпрд╛ project рд╡рд░
(pip install pytest), test_grades.py рдореНрд╣рдгреВрди save рдХрд░рд╛ рдЖрдгрд┐ pytest -q рдЪрд╛рд▓рд╡рд╛:
from exam.grades import grade
def test_half_mark_rounds_up_to_a_pass():
assert grade(34.5) == "D"
pytest рд╕рд╛рдзреЗ assert рдкреБрдиреНрд╣рд╛ рд▓рд┐рд╣рд┐рддреЗ, рдореНрд╣рдгреВрди failure рдордзреНрдпреЗ рджреЛрдиреНрд╣реА рдмрд╛рдЬреВ рджрд┐рд╕рддрд╛рдд:
E AssertionError: assert 'F' == 'D'
Python рдЪреЗ рд╕реНрд╡рддрдГрдЪреЗ documentation рдпрд╛рдЪ рд╕рд╛рдкрд│реНрдпрд╛рдмрджреНрджрд▓ рдЗрд╢рд╛рд░рд╛ рджреЗрддреЗ: round(2.5) рдореНрд╣рдгрдЬреЗ 2, рдХрд╛рд░рдг
round() round-half-to-even ("banker's rounding") рд╡рд╛рдкрд░рддреЗ, рдЖрдгрд┐ 2.675 рд╕рд╛рд░рдЦреЗ floats
рдЕрд░реНрдзреНрдпрд╛рдЪреНрдпрд╛ рдереЛрдбреЗ рдЦрд╛рд▓реА рд╕рд╛рдард╡рд▓реЗ рдЬрд╛рддрд╛рдд. рдкреИрд╕реЗ рдХрд┐рдВрд╡рд╛ рдЧреБрдгрд╛рдВрд╕рд╛рдареА рдард░рд╛рд╡рд┐рдХ рдирд╛рд╡рд╛рдЪрд╛ рдирд┐рдпрдо рд╣рд╡рд╛ рдЕрд╕реЗрд▓, рддрд░ decimal рд╡рд╛рдкрд░рд╛:
from decimal import Decimal, ROUND_HALF_UP
Decimal("34.5").quantize(Decimal(1), rounding=ROUND_HALF_UP) # Decimal('35')
ЁЯПн Production рдордзреНрдпреЗ рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: business рдордзрд▓реА рд╡реНрдпрдХреНрддреА рдПрдХрд╛ рд╡рд╛рдХреНрдпрд╛рдд рд╕рд╛рдВрдЧреВ рд╢рдХреЗрд▓ рдЕрд╢рд╛ рдкреНрд░рддреНрдпреЗрдХ рдирд┐рдпрдорд╛рд╕рд╛рдареА ("35 рдореНрд╣рдгрдЬреЗ pass", "рдЕрд░реНрдзрд╛ рд╡рд░ round рд╣реЛрддреЛ", "тВ╣500 рд╡рд░реАрд▓ orders рдореЛрдлрдд ship рд╣реЛрддрд╛рдд"), рддреЗрдЪ рд╡рд╛рдХреНрдп code рдордзреНрдпреЗ рд╕рд╛рдВрдЧрдгрд╛рд░рд╛ test рдЕрд╕рд╛рдпрд▓рд╛ рд╣рд╡рд╛ тАФ рдиреЗрдордХреНрдпрд╛ рдХрдбреЗрд╕рд╣.
тПня╕П рдкреБрдвреЗ
рдПрдХ рдкреНрд░рд╢реНрди рдореНрд╣рдгрдЬреЗ рдПрдХ test. рддреЛ рдЪрд╛рдВрдЧрд▓рд╛ рдХрд╕рд╛ рд▓рд┐рд╣рд╛рдпрдЪрд╛, рдЖрдгрд┐ рдЕрдиреЗрдХ рдХрд╕реЗ рдЪрд╛рд▓рд╡рд╛рдпрдЪреЗ? Arrange, act, assert,
рддреБрдордЪреНрдпрд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ runner рдордзреНрдпреЗ рдЖрдгрд┐ standard library рдЪреНрдпрд╛ unittest рдордзреНрдпреЗ.
git checkout lesson-02-unit-tests