ЁЯзм рдзрдбрд╛ 10 тАФ Coverage рд╡рд┐рд░реБрджреНрдз mutation testing: 100% рдЬреА рдлрдХреНрдд рдХрд╛рд╣реА mutants рдорд╛рд░рддреЗ
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 10 ┬╖ рдорд╛рдЧреАрд▓: lesson-09-property-based ┬╖ рдкреБрдвреАрд▓: lesson-11-flaky-tests
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ09, рдЖрдгрд┐ рддреНрдпрд╛рд╢рд┐рд╡рд╛рдп tests рдЪреАрдЪ рдкрд░реАрдХреНрд╖рд╛ рдШреЗрдгреНрдпрд╛рдЪреЗ рджреЛрди рдорд╛рд░реНрдЧ: line coverage (suite
рдЪрд╛рд▓рддрд╛рдирд╛ grade() рдЪреНрдпрд╛ рдХреЛрдгрддреНрдпрд╛ lines рдЪрд╛рд▓рд▓реНрдпрд╛) рдЖрдгрд┐ mutation testing (grade() рдордзреНрдпреЗ рдЫреЛрдЯреЗ bugs
тАФ mutants тАФ рдкреЗрд░рд╛ рдЖрдгрд┐ suite рддреНрдпрд╛рддрд▓реЗ рдХрд┐рддреА рдкрдХрдбрддреЛ рддреЗ рдореЛрдЬрд╛). 100% line coverage рдЕрд╕рд▓реЗрд▓рд╛ suite
10 рдкреИрдХреА рдлрдХреНрдд 4 mutants рдорд╛рд░рддреЛ. line_coverage(), MUTANTS, mutation_run(), WEAK рдЖрдгрд┐
STRONG exam/lab.py рдордзреНрдпреЗ; mutation() exam/demo.py
рдордзреНрдпреЗ.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдХрддрд░рд┐рдирд╛рд▓рд╛ рдлрдХреНрдд рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдирд╡реНрд╣реЗ, рддрд░ рддрд┐рдЪреА рдкреНрд░рд╢реНрдирдкрддреНрд░рд┐рдХрд╛ рдЪрд╛рдВрдЧрд▓реА рдЖрд╣реЗ рдХрд╛ рд╣реЗ рдЬрд╛рдгреВрди рдШреНрдпрд╛рдпрдЪреЗ рдЖрд╣реЗ.
рдкрд╣рд┐рд▓реА рдХрд▓реНрдкрдирд╛: coverage. ЁЯУЛ рдкрд╛рдареНрдпрдкреБрд╕реНрддрдХрд╛рдЪреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ рдкрд╛рдирд╛рд▓рд╛ рдХрд┐рдорд╛рди рдПрдХрд╛ рдкреНрд░рд╢реНрдирд╛рдиреЗ рд╕реНрдкрд░реНрд╢ рдХреЗрд▓рд╛ рдХрд╛ рд╣реЗ рддреА рддрдкрд╛рд╕рддреЗ. 7 рдкреНрд░рд╢реНрдирд╛рдВрдЪреА рдХрдордХреБрд╡рдд рдкреНрд░рд╢реНрдирдкрддреНрд░рд┐рдХрд╛ рдкреНрд░рддреНрдпреЗрдХ рдкрд╛рдирд╛рд▓рд╛ рд╕реНрдкрд░реНрд╢ рдХрд░рддреЗ: 100%! ЁЯОЙ
рджреБрд╕рд░реА рдХрд▓реНрдкрдирд╛: mutants. ЁЯзм рдРрд╢реНрд╡рд░реНрдпрд╛ рдЧреБрдкрдЪреВрдк рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреАрдЪреНрдпрд╛ 10 рдкреНрд░рддреА рдмрдирд╡рддреЗ, рдкреНрд░рддреНрдпреЗрдХреАрдд рдПрдХ рдЫреЛрдЯреА рдЪреВрдХ: рдПрдХреАрд▓рд╛ рд╡рд╛рдЯрддреЗ pass рд╣реЛрдгреНрдпрд╛рд╕рд╛рдареА рдХрд┐рдорд╛рди 35 рдирд╡реНрд╣реЗ рддрд░ 35 рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рд╣рд╡реЗрдд; рдПрдХ рдЕрд░реНрдзреЗ рдЧреБрдг рдЬреБрдиреНрдпрд╛ рдЪреБрдХреАрдЪреНрдпрд╛ рдкрджреНрдзрддреАрдиреЗ round рдХрд░рддреЗ; рдПрдХ рдЬрд┐рдереЗ "A" рдмрд░реЛрдмрд░ рд╣реЛрддрд╛ рддрд┐рдереЗ "B" рджреЗрддреЗ. рдордЧ рдХрддрд░рд┐рдирд╛рдЪреА рдкреНрд░рд╢реНрдирдкрддреНрд░рд┐рдХрд╛ рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рддреАрд▓рд╛ рджрд┐рд▓реА рдЬрд╛рддреЗ.
- рдкреНрд░рд╢реНрдирдкрддреНрд░рд┐рдХреЗрдиреЗ рдЪреВрдХ рдкрдХрдбрд▓реА, рддрд░ рддреЛ mutant рдорд╛рд░рд▓рд╛ рдЧреЗрд▓рд╛ (killed). тЬЕ
- рдкреНрд░рдд рдкреНрд░рд╢реНрдирдкрддреНрд░рд┐рдХрд╛ рддрд░реАрд╣реА pass рдЭрд╛рд▓реА, рддрд░ mutant рдЯрд┐рдХрд▓рд╛ (survived) тАФ рдкреНрд░рд╢реНрдирдкрддреНрд░рд┐рдХреЗрд▓рд╛ рдЪреБрдХреАрдЪреА рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдЖрдгрд┐ рдмрд░реЛрдмрд░ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдпрд╛рдВрддрд▓рд╛ рдлрд░рдХ рдУрд│рдЦрддрд╛ рдЖрд▓рд╛ рдирд╛рд╣реА. тЭМ
100% coverage рдЕрд╕рд▓реЗрд▓реА рдХрдордХреБрд╡рдд рдкреНрд░рд╢реНрдирдкрддреНрд░рд┐рдХрд╛ 10 рдкреИрдХреА рдлрдХреНрдд 4 рдорд╛рд░рддреЗ. рддрд┐рдиреЗ рдкреНрд░рддреНрдпреЗрдХ рдкрд╛рдирд╛рд▓рд╛ рд╕реНрдкрд░реНрд╢ рдХреЗрд▓рд╛, рдкрдг рдХрдбрд╛рдВрдмрджреНрджрд▓ рдХрдзреАрдЪ рд╡рд┐рдЪрд╛рд░рд▓реЗ рдирд╛рд╣реА. рдзрдбрд╛ 03 рдордзрд▓реНрдпрд╛ boundary рдкреНрд░рд╢реНрдирд╛рдВрд╕рд╣ рдЕрд╕рд▓реЗрд▓реА рдордЬрдмреВрдд рдкреНрд░рд╢реНрдирдкрддреНрд░рд┐рдХрд╛ 9 рдорд╛рд░рддреЗ.
рдЖрдгрд┐ 10рд╡рд╛? рддреНрдпрд╛рдиреЗ "рдХрд┐рдорд╛рди 75" рдЪреЗ "74 рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд" рдХреЗрд▓реЗ. рдкреВрд░реНрдг рд╕рдВрдЦреНрдпрд╛рдВрд╕рд╛рдареА рд╣рд╛ рддреЛрдЪ рдирд┐рдпрдо рдЖрд╣реЗ. рдХреЛрдгрддрд╛рд╣реА рдкреНрд░рд╢реНрди рддреНрдпрд╛рд▓рд╛ рдХрдзреАрдЪ рдкрдХрдбреВ рд╢рдХрдд рдирд╛рд╣реА, рдХрд╛рд░рдг рддреА рдЪреВрдХрдЪ рдирд╛рд╣реА. рддреНрдпрд╛рд▓рд╛рдЪ equivalent mutant рдореНрд╣рдгрддрд╛рдд.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
subgraph weak["ЁЯУД WEAK suite: 7 questions"]
w["coverage 12/12 = 100%<br/>mutants killed 4/10"]
end
subgraph strong["ЁЯУС STRONG suite: 21 questions"]
s["coverage 12/12 = 100%<br/>mutants killed 9/10"]
end
weak -->|"add boundary questions<br/>34.5 ┬╖ 35 ┬╖ 60 ┬╖ 74.5 ┬╖ 75 ┬╖ 100.1"| strong
strong --> eq["the survivor: s >= 75 тЖТ s > 74<br/>EQUIVALENT for whole numbers"]
ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрдХреГрддреА + рдПрдХ lab: https://school-edh.pages.dev/testing/lesson-diagrams.html#l10
тЭУ рдХрд╛рдп
- Line (statement) coverage тАФ tests рджрд░рдореНрдпрд╛рди рдХрд┐рдорд╛рди рдПрдХрджрд╛ рдЪрд╛рд▓рд▓реЗрд▓реНрдпрд╛ executable lines рдЪрд╛ рд╡рд╛рдЯрд╛.
grade()рдордзреНрдпреЗ 12 statement lines рдЖрд╣реЗрдд. - Branch coverage тАФ рдШреЗрддрд▓реЗрд▓реНрдпрд╛ branch рджрд┐рд╢рд╛рдВрдЪрд╛ рд╡рд╛рдЯрд╛ (рдкреНрд░рддреНрдпреЗрдХ
iftrue рдЖрдгрд┐ false рджреЛрдиреНрд╣реА). Line coverage рдкреЗрдХреНрд╖рд╛ рдХрдбрдХ, рдкрдг рддрд░реАрд╣реА asserts рдмрджреНрджрд▓ рдХрд╛рд╣реАрдЪ рд╕рд╛рдВрдЧрдд рдирд╛рд╣реА. - Coverage рдХрд╛рдп рд╕рд╛рдВрдЧрддреЗ тАФ рдЬреНрдпрд╛ lines рдХрдзреАрдЪ рдЪрд╛рд▓рд▓реНрдпрд╛ рдирд╛рд╣реАрдд рддреНрдпрд╛ рдирдХреНрдХреАрдЪ test рдЭрд╛рд▓реЗрд▓реНрдпрд╛ рдирд╛рд╣реАрдд. рдЬреНрдпрд╛ рдЪрд╛рд▓рд▓реНрдпрд╛ рддреНрдпрд╛рд╣реА рддрдкрд╛рд╕рд▓реЗрд▓реНрдпрд╛ рдирд╕реВ рд╢рдХрддрд╛рдд: assert рдирд╕рд▓реЗрд▓реА test рд╕реБрджреНрдзрд╛ рдкреВрд░реНрдг coverage рджреЗрддреЗ.
- Mutant тАФ mutation operator рдиреЗ рдХреЗрд▓реЗрд▓рд╛ рдПрдХ рдЫреЛрдЯрд╛ рдмрджрд▓ рдЕрд╕рд▓реЗрд▓реА code рдЪреА copy:
>=тЖТ>,andтЖФor, рдПрдЦрд╛рджрд╛ constant ┬▒ 1, рд╡реЗрдЧрд│реА return value, рдмрджрд▓рд▓реЗрд▓рд╛ call. - Killed / survived тАФ mutant рд╡рд░ рдХрд┐рдорд╛рди рдПрдХ test fail рдЭрд╛рд▓реА рддрд░ killed; рдкреВрд░реНрдг suite рддрд░реАрд╣реА pass рдЭрд╛рд▓рд╛ рддрд░ survived. рдЯрд┐рдХрд▓реЗрд▓рд╛ mutant рдПрдЦрд╛рджреНрдпрд╛ рдирд╕рд▓реЗрд▓реНрдпрд╛ рдХрд┐рдВрд╡рд╛ рдХрдордХреБрд╡рдд test рдХрдбреЗ рдмреЛрдЯ рджрд╛рдЦрд╡рддреЛ.
- Equivalent mutant тАФ рд╡рд╛рдЧрдгреВрдХ рди рдмрджрд▓рдгрд╛рд░рд╛ рдмрджрд▓ (рдЗрдереЗ,
sрдкреВрд░реНрдг рд╕рдВрдЦреНрдпрд╛ рдЕрд╕рддрд╛рдирд╛s >= 75рд╡рд┐рд░реБрджреНрдзs > 74). рдХреЛрдгрддреАрд╣реА test рддреНрдпрд╛рд▓рд╛ рдорд╛рд░реВ рд╢рдХрдд рдирд╛рд╣реА; tools рдирд╛ рддреЗ рдЦрд▒реНрдпрд╛ survivors рдкрд╛рд╕реВрди рдиреЗрд╣рдореА рд╡реЗрдЧрд│реЗ рдУрд│рдЦрддрд╛ рдпреЗрдд рдирд╛рд╣реАрдд, рдореНрд╣рдгреВрди рдПрдЦрд╛рджреНрдпрд╛ рдорд╛рдгрд╕рд╛рдиреЗ рдкрд╛рд╣рд╛рд╡реЗ рд▓рд╛рдЧрддреЗ. - Mutation score тАФ killed ├╖ (рд╕рд░реНрд╡ mutants тИТ equivalent mutants). рдЗрдереЗ рдордЬрдмреВрдд suite рдЪрд╛ score 9 ├╖ 9 = 100%, рдХрдордХреБрд╡рддрдЪрд╛ 4 ├╖ 9 тЙИ 44%.
- рдХрд┐рдВрдордд тАФ рдкреНрд░рддреНрдпреЗрдХ mutant рд╕рд╛рдареА suite рдкреБрдиреНрд╣рд╛ рдЪрд╛рд▓рддреЛ. рдЦрд░реЗ tools рд╣рдЬрд╛рд░реЛ mutants рдмрдирд╡рддрд╛рдд, рдореНрд╣рдгреВрди рддреЗ рдкреНрд░рддреНрдпреЗрдХ рдмрджрд▓рд▓реЗрд▓реА line cover рдХрд░рдгрд╛рд▒реНрдпрд╛ tests рдЪ рдЪрд╛рд▓рд╡рддрд╛рдд, рдЖрдгрд┐ рдмрд▒реНрдпрд╛рдЪрджрд╛ рд░рд╛рддреНрд░реА рдХрд┐рдВрд╡рд╛ рдлрдХреНрдд рдмрджрд▓рд▓реЗрд▓реНрдпрд╛ code рд╡рд░ рдЪрд╛рд▓рд╡рд▓реЗ рдЬрд╛рддрд╛рдд.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг coverage рдореЛрдЬрд╛рдпрд▓рд╛ рд╕реЛрдкреА рдЖрдгрд┐ рдлрд╕рд╡рд╛рдпрд▓рд╛рд╣реА рд╕реЛрдкреА рдЖрд╣реЗ, рдЖрдгрд┐ teams рдЕрд╕реЗ coverage targets рдард░рд╡рддрд╛рдд рдЬреЗ
assert рдирд╕рд▓реЗрд▓реНрдпрд╛ tests рд╕реБрджреНрдзрд╛ рдЧрд╛рдареВ рд╢рдХрддрд╛рдд. Mutation testing рддреБрдореНрд╣рд╛рд▓рд╛ рдЦрд░реЛрдЦрд░ рд╣рд╡реЗ рддреЗ рдореЛрдЬрддреЗ: suite
рд▓рд╛ bug рд▓рдХреНрд╖рд╛рдд рдпреЗрдИрд▓ рдХрд╛? рдЯрд┐рдХрд▓реЗрд▓реЗ mutants рдореНрд╣рдгрдЬреЗ рдиреЗрдордХреЗ рдХреЛрдгрддреЗ рдкреНрд░рд╢реНрди рд░рд╛рд╣рд┐рд▓реЗ рдЖрд╣реЗрдд рдпрд╛рдЪреА рдпрд╛рджреА тАФ
score > 100 тЖТ score > 101 рдЯрд┐рдХрд▓рд╛ рдореНрд╣рдгрдЬреЗ "100.1 рдмрджреНрджрд▓ рдХреЛрдгреАрдЪ рд╡рд┐рдЪрд╛рд░рд▓реЗ рдирд╛рд╣реА".
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
exam/lab.py рдордзреАрд▓ line_coverage(fn, suite) sys.settrace рдиреЗ рдПрдХ trace
function рд▓рд╛рд╡рддреЗ, suite рдЪрд╛рд▓рддрд╛рдирд╛ fn рдЪреНрдпрд╛ code object рдордзреАрд▓ рдкреНрд░рддреНрдпреЗрдХ line event рдиреЛрдВрджрд╡рддреЗ, рдЖрдгрд┐ fn
рдЪрд╛ source ast рдиреЗ parse рдХрд░реВрди рд╕рд╛рдкрдбрд▓реЗрд▓реНрдпрд╛ statement lines рд╢реА рддреБрд▓рдирд╛ рдХрд░рддреЗ. MUTANTS рдордзреНрдпреЗ 10
(рдЬреБрдирд╛ рдордЬрдХреВрд░, рдирд╡рд╛ рдордЬрдХреВрд░) рдЬреЛрдбреНрдпрд╛ рдЖрд╣реЗрдд; mutant(old, new) grade() рдЪрд╛ source рдкреБрдиреНрд╣рд╛ рд▓рд┐рд╣рд┐рддреЗ рдЖрдгрд┐
рдирд╡реНрдпрд╛ namespace рдордзреНрдпреЗ exec рдХрд░рддреЗ. mutation_run(suite) рдкреНрд░рддреНрдпреЗрдХ mutant рд╡рд░ suite рдЪрд╛рд▓рд╡рддреЗ рдЖрдгрд┐
рдХреЛрдгрддрд╛ case fail рдЭрд╛рд▓рд╛ рдХрд╛ рддреЗ рдиреЛрдВрджрд╡рддреЗ. WEAK рдордзреНрдпреЗ рд╡рд░реНрдЧрд╛рдЪреНрдпрд╛ рдордзрд▓реНрдпрд╛ рднрд╛рдЧрд╛рддрд▓реЗ 7 cases рдЖрд╣реЗрдд; STRONG
рддреНрдпрд╛рдд рдзрдбрд╛ 03 рдордзрд▓рд╛ boundary table рдЬреЛрдбрддреЛ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 exam/demo.py mutation
python3 - <<'EOF'
from exam.lab import line_coverage, mutation_run, statement_lines, WEAK, STRONG
from exam.grades import grade
print("statement lines of grade():", statement_lines(grade))
for name, suite in (("one question", [(90, "A")]), ("WEAK", WEAK), ("WEAK + 3 edges", WEAK + [(34.5, "D"), (75, "A"), (100.1, ValueError)]), ("STRONG", STRONG)):
hit, total = line_coverage(grade, suite)
res = mutation_run(suite)
print(f"{name:<15} coverage {hit:>2}/{total} ┬╖ killed {sum(k for *_, k in res):>2}/10 ┬╖ survivors {[n for o, n, k in res if not k]}")
EOF
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
mutation рд╣реЗ рдЫрд╛рдкрддреЗ:
тФАтФА WEAK suite (7 questions): line coverage of grade() 12/12 = 100% ┬╖ mutants killed 4/10
s >= 75 тЖТ s > 75 SURVIVED
s >= 35 тЖТ s > 35 SURVIVED
s >= 60 тЖТ s >= 61 SURVIVED
round_half_up(score) тЖТ round(score) SURVIVED
return "A" тЖТ return "B" killed
тФАтФА STRONG suite (21 questions): line coverage of grade() 12/12 = 100% ┬╖ mutants killed 9/10
рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:
statement lines of grade(): [27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38]
one question coverage 4/12 ┬╖ killed 1/10 ┬╖ survivors ['s > 75', 's > 35', 's >= 61', 'round(score)', 'return "D"', 'score < 0 and', 's <= 45', 'score > 101', 's > 74']
WEAK coverage 12/12 ┬╖ killed 4/10 ┬╖ survivors ['s > 75', 's > 35', 's >= 61', 'round(score)', 'score > 101', 's > 74']
WEAK + 3 edges coverage 12/12 ┬╖ killed 8/10 ┬╖ survivors ['s >= 61', 's > 74']
STRONG coverage 12/12 ┬╖ killed 9/10 ┬╖ survivors ['s > 74']
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
7 рдкреНрд░рд╢реНрдирд╛рдВрдирдВрддрд░ coverage рдЪреА рдорджрдд рдерд╛рдВрдмрд▓реА: WEAK рдкрд╛рд╕реВрди STRONG рдкрд░реНрдпрдВрдд рддреА 100% рд╡рд░рдЪ рд░рд╛рд╣рд┐рд▓реА, рддрд░
рдорд╛рд░рд▓реЗрд▓реНрдпрд╛рдВрдЪреА рд╕рдВрдЦреНрдпрд╛ 4 рд╡рд░реВрди 9 рдЭрд╛рд▓реА. WEAK suite рдиреЗ рдзрдбрд╛ 01 рдордзреНрдпреЗ ship рдЭрд╛рд▓реЗрд▓рд╛ рдиреЗрдордХрд╛ bug тАФ
round_half_up(score) тЖТ round(score) тАФ рдкреВрд░реНрдг coverage рдЕрд╕реВрдирд╣реА рдЯрд┐рдХреВ рджрд┐рд▓рд╛. рдиреАрдЯ рдирд┐рд╡рдбрд▓реЗрд▓реНрдпрд╛ рддреАрди
рдХрдбреЗрдЪреНрдпрд╛ рдкреНрд░рд╢реНрдирд╛рдВрдиреА рдЖрдгрдЦреА рдЪрд╛рд░ mutants рдорд╛рд░рд▓реЗ, рдЖрдгрд┐ рдЙрд░рд▓реЗрд▓реНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ survivor рдиреЗ рдЕрдЬреВрди рдХреЛрдгрддрд╛ рдкреНрд░рд╢реНрди
рд░рд╛рд╣рд┐рд▓рд╛ рдЖрд╣реЗ рддреЗ рд╕рд╛рдВрдЧрд┐рддрд▓реЗ (s >= 61 рд╕рд╛рдареА рдиреЗрдордХреНрдпрд╛ 60 рд╡рд░ рдкреНрд░рд╢реНрди рд╣рд╡рд╛). рд╢реЗрд╡рдЯрдЪрд╛, s > 74, equivalent
рдЖрд╣реЗ: рддрд┐рдереЗ рдерд╛рдВрдмрд╛.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- coverage target (рд╕рдордЬрд╛ 80%) рд▓рд╛ quality target рдорд╛рдирдгреЗ тАФ рддреА рдлрдХреНрдд рдХрд┐рдорд╛рди рдкрд╛рддрд│реА рдЖрд╣реЗ
- coverage рд╡рд╛рдврд╡рдгреНрдпрд╛рд╕рд╛рдареА рд▓рд┐рд╣рд┐рд▓реЗрд▓реНрдпрд╛, code рдмреЛрд▓рд╡рдгрд╛рд▒реНрдпрд╛ рдкрдг assert рди рдХрд░рдгрд╛рд▒реНрдпрд╛ tests
- рдкреНрд░рддреНрдпреЗрдХ commit рд╡рд░ рдкреВрд░реНрдг code base рд╡рд░ mutation testing рдЪрд╛рд▓рд╡рдгреЗ (рдмрджрд▓рд▓реЗрд▓реНрдпрд╛ code рд╡рд░, рдХрд┐рдВрд╡рд╛ рд░рд╛рддреНрд░реА рдЪрд╛рд▓рд╡рд╛)
- equivalent mutants рдЪреНрдпрд╛ рдорд╛рдЧреЗ рддрд╛рд╕рдиреНрддрд╛рд╕ рдзрд╛рд╡рдгреЗ
- line coverage 100% рдЕрд╕рддрд╛рдирд╛ branch coverage рдХрдбреЗ рджреБрд░реНрд▓рдХреНрд╖ рдХрд░рдгреЗ
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
рдЦрд▒реНрдпрд╛ project рдордзреНрдпреЗ тАФ coverage.py рдХрд┐рдВрд╡рд╛ pytest-cov plugin рдиреЗ coverage; -m рдЖрдгрд┐
term-missing рдХрдзреАрдЪ рди рдЪрд╛рд▓рд▓реЗрд▓реНрдпрд╛ lines рдЪреА рдпрд╛рджреА рджреЗрддрд╛рдд:
pip install coverage pytest pytest-cov
coverage run --branch -m pytest && coverage report -m
pytest --cov=exam --cov-branch --cov-report=term-missing --cov-fail-under=90
mutmut рдиреЗ mutation testing (Python; рддреЗ рддреБрдордЪрд╛ pytest suite рдкреНрд░рддреНрдпреЗрдХ mutant рд╡рд░ рдЪрд╛рд▓рд╡рддреЗ):
pip install mutmut
mutmut run # generate mutants and run the tests against each one
mutmut results # list the survivors
mutmut show <mutant> # the diff of one survivor
рдЗрддрд░ tools: Java рд╕рд╛рдареА PIT (PITest), JavaScript/TypeScript, C# рдЖрдгрд┐ Scala рд╕рд╛рдареА Stryker, Python рд╕рд╛рдареА cosmic-ray. Google рдиреЗ рд╕рд╛рдВрдЧрд┐рддрд▓реЗ рдЖрд╣реЗ рдХреА рддреЗ рдЯрд┐рдХрд▓реЗрд▓реЗ mutants project-wide score рдореНрд╣рдгреВрди рдирд╡реНрд╣реЗ, рддрд░ code review рдордзреНрдпреЗ comments рдореНрд╣рдгреВрди, рдлрдХреНрдд рдмрджрд▓рд▓реЗрд▓реНрдпрд╛ lines рд╡рд░ рджрд╛рдЦрд╡рддрд╛рдд.
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: test рди рдЭрд╛рд▓реЗрд▓реНрдпрд╛ code рд╕рд╛рдареА coverage рдПрдХ рд╕реНрд╡рд╕реНрдд рдзреЛрдХреНрдпрд╛рдЪреА рдШрдВрдЯрд╛ рдореНрд╣рдгреВрди рдареЗрд╡рд╛, рдЖрдгрд┐ рдЬрд┐рдереЗ рдЪреБрдХреАрдЪреЗ рдЙрддреНрддрд░ рдорд╣рд╛рдЧ рдкрдбрддреЗ рдЕрд╢рд╛ рдереЛрдбреНрдпрд╛ modules рд╡рд░ mutation testing рдЪрд╛рд▓рд╡рд╛ тАФ grading, billing, permissions. рдкреНрд░рддреНрдпреЗрдХ survivor рдореНрд╣рдгрдЬреЗ рдПрдХрддрд░ рдирд╕рд▓реЗрд▓реА test рдХрд┐рдВрд╡рд╛ equivalent mutant; рджреЛрдиреНрд╣реА рдорд╛рд╣реАрдд рдЕрд╕рдгреЗ рдлрд╛рдпрджреНрдпрд╛рдЪреЗ рдЖрд╣реЗ.
тПня╕П рдкреБрдвреЗ
рдЪрд╛рдВрдЧрд▓рд╛ suite рд╕реБрджреНрдзрд╛ рджреБрд╕рд▒реНрдпрд╛ рдкреНрд░рдХрд╛рд░реЗ рдЦреЛрдЯреЗ рдмреЛрд▓реВ рд╢рдХрддреЛ: code рдордзреНрдпреЗ рдХрд╛рд╣реАрд╣реА рдмрджрд▓ рди рдХрд░рддрд╛ рд╕реЛрдорд╡рд╛рд░реА pass рдЖрдгрд┐ рдордВрдЧрд│рд╡рд╛рд░реА fail рд╣реЛрдгрд╛рд░реА test. рднрд┐рдВрддреАрд╡рд░рдЪреЗ рдбреБрдЧрдбреБрдЧрдгрд╛рд░реЗ рдШрдбреНрдпрд╛рд│ тАФ flaky tests.
git checkout lesson-11-flaky-tests