ЁЯЪж рдзрдбрд╛ 12 тАФ CI рдордзреАрд▓ tests рдЖрдгрд┐ TDD: red, green, refactor тАФ рдЖрдгрд┐ рд╕рдВрдкреВрд░реНрдг рдЪрд┐рддреНрд░
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 12 ┬╖ рдорд╛рдЧреАрд▓: lesson-11-flaky-tests
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ11, рдЖрдгрд┐ рддреНрдпрд╛рд╢рд┐рд╡рд╛рдп tests рдХрдзреА рдЪрд╛рд▓рддрд╛рдд. Test-driven development (TDD) рдЙрддреНрддрд░рд╛рдЪреНрдпрд╛
рдЖрдзреА рдкрд░реАрдХреНрд╖реЗрдЪрд╛ рдкреНрд░рд╢реНрди рд▓рд┐рд╣рд┐рддреЗ: red, green, refactor. Continuous integration (CI) рдкреНрд░рддреНрдпреЗрдХ
рдмрджрд▓рд╛рд╡рд░ suite рдЪрд╛рд▓рд╡рддреЗ, рд╡реЗрдЧрд╡рд╛рди рддрдкрд╛рд╕рдгреНрдпрд╛ рдЖрдзреА, рдЖрдгрд┐ test selection рдмрджрд▓рд╛рдЪрд╛ рдкрд░рд┐рдгрд╛рдо рд╣реЛрдК рд╢рдХрдгрд╛рд▒реНрдпрд╛
tests рдЪ рдлрдХреНрдд рдЪрд╛рд▓рд╡рддреЗ. grace_v0, grace_v1, grace_v2, GRACE_TESTS, SUITES рдЖрдгрд┐
select_tests() exam/lab.py рдордзреНрдпреЗ; ci() exam/demo.py
рдордзреНрдпреЗ. рдЖрдгрд┐ рд╕рдВрдкреВрд░реНрдг рдХреЛрд░реНрд╕ рдПрдХрд╛ рдкрд╛рдирд╛рд╡рд░.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рд╢рд╛рд│реЗрдЪрд╛ рдПрдХ рдирд╡рд╛ рдирд┐рдпрдо рдпреЗрддреЛ: "рдЬреА рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА 35 рдкрд╛рд╕реВрди 2 рдЧреБрдг рдХрд┐рдВрд╡рд╛ рддреНрдпрд╛рд╣реВрди рдХрдореА рдорд╛рдЧреЗ рдЖрд╣реЗ, рдЖрдгрд┐ рдЬрд┐рдЪреНрдпрд╛рдХрдбреЗ medical note рдЖрд╣реЗ, рддрд┐рд▓рд╛ 35 рдкрд░реНрдпрдВрдд рд╡рд░ рдШреНрдпрд╛рд╡реЗ."
рдХрддрд░рд┐рдирд╛ рдПрдХ рд╡реЗрдЧрд│реАрдЪ рдЧреЛрд╖реНрдЯ рдХрд░рддреЗ. рддреА рдЖрдзреА рдкрд░реАрдХреНрд╖реЗрдЪреЗ рдкреНрд░рд╢реНрди ЁЯУЭ рд▓рд┐рд╣рд┐рддреЗ тАФ рдкрд╛рдЪ: note рд╕рд╣ 33 тЖТ 35; note рд╕рд╣ 34.9 тЖТ 35; note рд╢рд┐рд╡рд╛рдп 33 тЖТ 33; note рд╕рд╣ 32.9 тЖТ 32.9; note рд╕рд╣ 35 тЖТ 35. рддреА рддреЗ рдЪрд╛рд▓рд╡рддреЗ. рдкрд╛рдЪрд╣реА fail рд╣реЛрддрд╛рдд тАФ рдЕрдЬреВрди code рдЪ рдирд╛рд╣реА. ЁЯФ┤ рд╣реЗ red. рдпрд╛рд╡рд░реВрди рд╕рд┐рджреНрдз рд╣реЛрддреЗ рдХреА рдкреНрд░рд╢реНрди fail рд╣реЛрдК рд╢рдХрддрд╛рдд.
рджреАрдкрд┐рдХрд╛ pass рд╣реЛрдгрд╛рд░рд╛ рд╕рд░реНрд╡рд╛рдд рд╕рд╛рдзрд╛ code рд▓рд┐рд╣рд┐рддреЗ. рдкреБрдиреНрд╣рд╛ рдЪрд╛рд▓рд╡рд╛: 5 рдкреИрдХреА 5. ЁЯЯв Green.
рдордЧ рджреАрдкрд┐рдХрд╛ рддреЛ рдиреАрдЯрдиреЗрдЯрдХрд╛ рдХрд░рддреЗ тАФ "2 рдЧреБрдг" рд▓рд╛ рдПрдХ рдирд╛рд╡ рджреЗрддреЗ, рд╢рд╛рд│реЗрдЪрд╛ pass-mark constant рд╡рд╛рдкрд░рддреЗ. рдкреБрдиреНрд╣рд╛ рдЪрд╛рд▓рд╡рд╛: рддрд░реАрд╣реА 5 рдкреИрдХреА 5. ЁЯФ╡ Refactor рдЭрд╛рд▓реЗ, рд╕реБрд░рдХреНрд╖рд┐рддрдкрдгреЗ.
рдЖрдгрд┐ рдЬреЗрд╡реНрд╣рд╛ рдЬреЗрд╡реНрд╣рд╛ рдХреЛрдгреА рдХрд╛рд╣реАрд╣реА рдмрджрд▓рддреЗ, рддреЗрд╡реНрд╣рд╛ рдРрд╢реНрд╡рд░реНрдпрд╛рдЪрд╛ CI рд╣реЙрд▓ ЁЯЪж рдкреНрд░рд╢реНрди рдЖрдкреЛрдЖрдк рдЪрд╛рд▓рд╡рддреЛ: рдЖрдзреА рдЭрдЯрдкрдЯ рдкреНрд░рд╢реНрди, рдЖрдгрд┐ рдлрдХреНрдд рддреНрдпрд╛рдЪ рдкреНрд░рд╢реНрдирдкрддреНрд░рд┐рдХрд╛ рдЬреНрдпрд╛рдВрдЪреНрдпрд╛рд╡рд░ рдмрджрд▓рд╛рдЪрд╛ рдкрд░рд┐рдгрд╛рдо рд╣реЛрдК рд╢рдХрддреЛ. Attendance code рдордзрд▓рд╛ рдмрджрд▓ рд╕рдЧрд│реЗ 105 рдирд╡реНрд╣реЗ, рддрд░ 28 рдкреНрд░рд╢реНрди рдЪрд╛рд▓рд╡рддреЛ. рдкрдг рдХреЛрдгрддреАрд╣реА рдЧреЛрд╖реНрдЯ main branch рдордзреНрдпреЗ рдЬрд╛рдгреНрдпрд╛рдЖрдзреА, рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╢реНрдирдкрддреНрд░рд┐рдХрд╛ рд╕реЛрдбрд╡рд▓реА рдЬрд╛рддреЗ.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
red["ЁЯФ┤ RED<br/>5 tests first, 0/5 pass"] --> green["ЁЯЯв GREEN<br/>simplest code, 5/5"]
green --> ref["ЁЯФ╡ REFACTOR<br/>name the rule, 5/5"]
ref -->|"push"| ci["ЁЯЪж CI: lint тЖТ unit тЖТ integration тЖТ contract тЖТ e2e"]
ci --> sel["change to attendance<br/>3 of 6 suites, 28 of 105 tests"]
ci --> main["merge to main<br/>all 105 tests"]
ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрдХреГрддреА + рдПрдХ lab: https://school-edh.pages.dev/testing/lesson-diagrams.html#l12
тЭУ рдХрд╛рдп
- TDD (test-driven development) тАФ Kent Beck, Test-Driven Development: By Example (2002). рдПрдХ рдЫреЛрдЯреЗ рдЪрдХреНрд░: red (рдкреБрдврдЪреНрдпрд╛ рдЫреЛрдЯреНрдпрд╛ рд╡рд╛рдЧрдгреБрдХреАрд╕рд╛рдареА fail рд╣реЛрдгрд╛рд░реА test рд▓рд┐рд╣рд╛), green (pass рд╣реЛрдгрд╛рд░рд╛ рд╕рд░реНрд╡рд╛рдд рд╕рд╛рдзрд╛ code), refactor (tests рдирд╛ рд╕реБрд░рдХреНрд╖рд╛-рдЬрд╛рд│реЗ рдорд╛рдиреВрди рд╕рд╛рдлрд╕рдлрд╛рдИ). TDD рдЪрд╛ defects рдЖрдгрд┐ рд╡реЗрдЧрд╛рд╡рд░ рд╣реЛрдгрд╛рд▒реНрдпрд╛ рдкрд░рд┐рдгрд╛рдорд╛рдЪреНрдпрд╛ рдЕрднреНрдпрд╛рд╕рд╛рдВрдЪреЗ рдирд┐рдХрд╛рд▓ рд╕рдВрдорд┐рд╢реНрд░ рдЖрд╣реЗрдд; рддреНрдпрд╛рдЪрд╛ рд╕рд░реНрд╡рд╛рдд рд╕реНрдкрд╖реНрдЯ рдлрд╛рдпрджрд╛ рдореНрд╣рдгрдЬреЗ test рдХрд░рддрд╛ рдпреЗрдгрд╛рд░реА design, рдЖрдгрд┐ рдкрд╣рд┐рд▓реНрдпрд╛ рджрд┐рд╡рд╕рд╛рдкрд╛рд╕реВрди рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рдЕрд╕рд▓реЗрд▓рд╛ suite.
- рдЖрдзреА red рдХрд╛ тАФ рдЬреА test рддреБрдореНрд╣реА рдХрдзреАрдЪ fail рд╣реЛрддрд╛рдирд╛ рдкрд╛рд╣рд┐рд▓реА рдирд╛рд╣реА, рддреА рдХрджрд╛рдЪрд┐рдд fail рд╣реЛрдКрдЪ рд╢рдХрдд рдирд╕реЗрд▓ (рдзрдбрд╛ 02 рдордзрд▓реА "assert рдирд╛рд╣реА" рд╣реА рдЪреВрдХ).
- Continuous integration (CI) тАФ рдкреНрд░рддреНрдпреЗрдХ рдмрджрд▓ рд╡рд╛рд░рдВрд╡рд╛рд░ merge рд╣реЛрддреЛ рдЖрдгрд┐ рдПрдХрд╛ server рд╡рд░ рдЖрдкреЛрдЖрдк build рдЖрдгрд┐ test рд╣реЛрддреЛ (GitHub Actions, GitLab CI, Jenkins, рдЖрдгрд┐ рдЗрддрд░).
- Fail fast тАФ pipeline рд╡реЗрдЧрд╛рдиреБрд╕рд╛рд░ рдорд╛рдВрдбрд╛: lint рдЖрдгрд┐ type checks (seconds), unit tests, integration, contract, рдордЧ рдереЛрдбреЗ e2e tests. рдкрд╣рд┐рд▓реНрдпрд╛ red рд╡рд░ рдерд╛рдВрдмрд╛.
- Test selection (test impact analysis) тАФ dependency map (Bazel рдЪрд╛ build graph), coverage data (pytest-testmon), рдХрд┐рдВрд╡рд╛ рдорд╛рдЧрдЪреНрдпрд╛ failures рд╡рд░ train рдХреЗрд▓реЗрд▓реЗ model (Meta рдЪреЗ predictive test selection) рд╡рд╛рдкрд░реВрди, рдмрджрд▓рд▓реЗрд▓реНрдпрд╛ code рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рдЕрд╕рд▓реЗрд▓реНрдпрд╛ tests рдЪ рдлрдХреНрдд рдЪрд╛рд▓рд╡рд╛. рдкреВрд░реНрдг suite рдХреБрдареЗ рдирд╛ рдХреБрдареЗ рдиреЗрд╣рдореА рдЪрд╛рд▓рд╡рд╛ тАФ merge рд╡реЗрд│реА рдХрд┐рдВрд╡рд╛ рд░рд╛рддреНрд░реА тАФ рдХрд╛рд░рдг map рдЪреБрдХреАрдЪрд╛ рдЕрд╕реВ рд╢рдХрддреЛ.
- Parallelism рдЖрдгрд┐ sharding тАФ suite CPU cores рдХрд┐рдВрд╡рд╛ machines рдордзреНрдпреЗ рд╡рд╛рдЯрд╛ (pytest-xdist, CI matrix jobs). рдлрдХреНрдд рд╕реНрд╡рддрдВрддреНрд░ tests рдЕрд╕рддреАрд▓ рддрд░рдЪ рд╕реБрд░рдХреНрд╖рд┐рдд (рдзрдбрд╛ 04).
- Required checks тАФ рдард░рд╡рд▓реЗрд▓реЗ CI jobs green рд╣реЛрдИрдкрд░реНрдпрдВрдд repository merge рдирд╛рдХрд╛рд░рддреЗ.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг test suite рдЪрд╛рд▓рд▓рд╛ рддрд░рдЪ рдЙрдкрдпреЛрдЧреА рдЕрд╕рддреЛ тАФ рдкреНрд░рддреНрдпреЗрдХ рдмрджрд▓рд╛рд╡рд░, рддреЛ рдмрджрд▓ рдЗрддрд░ рд╕рдЧрд│реНрдпрд╛рдВрдЪреНрдпрд╛ рдХрд╛рдорд╛рдд рдорд┐рд╕рд│рдгреНрдпрд╛рдЖрдзреА. TDD рдЦрд╛рддреНрд░реА рдХрд░рддреЗ рдХреА tests рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рдЖрд╣реЗрдд рдЖрдгрд┐ fail рд╣реЛрдК рд╢рдХрддрд╛рдд; CI рдЦрд╛рддреНрд░реА рдХрд░рддреЗ рдХреА рдХреЛрдгрд╛рд▓рд╛ рд▓рдХреНрд╖рд╛рдд рдареЗрд╡рд╛рд╡реЗ рди рд▓рд╛рдЧрддрд╛ рддреНрдпрд╛ рдЪрд╛рд▓рддрд╛рдд; selection рдЖрдгрд┐ рдХреНрд░рдо feedback рдЗрддрдХрд╛ рд╡реЗрдЧрд╡рд╛рди рдареЗрд╡рддрд╛рдд рдХреА рд▓реЛрдХ рддреНрдпрд╛рд▓рд╛ рд╡рд│рд╕рд╛ рдШрд╛рд▓рдгреНрдпрд╛рдРрд╡рдЬреА рддреНрдпрд╛рдЪреА рд╡рд╛рдЯ рдкрд╛рд╣рддрд╛рдд.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
exam/lab.py рдордзреАрд▓ GRACE_TESTS рдореНрд╣рдгрдЬреЗ рддреЗ рдкрд╛рдЪ рдкреНрд░рд╢реНрди; run_grace(fn) рддреЗ рдПрдХрд╛
рдЙрдореЗрджрд╡рд╛рд░ function рд╡рд░ рдЪрд╛рд▓рд╡рддреЗ рдЖрдгрд┐ NotImplementedError рд▓рд╛ fail рдорд╛рдирддреЗ. grace_v0 error рджреЗрддреЗ (red),
grace_v1 рд╣реА рдкрд╣рд┐рд▓реА pass рд╣реЛрдгрд╛рд░реА version, grace_v2 PASS_MARK рдЖрдгрд┐ lift parameter рд╡рд╛рдкрд░реВрди
рдирд┐рдпрдорд╛рд▓рд╛ рдирд╛рд╡ рджреЗрддреЗ. SUITES рд╣реЗ рдЦрд▒реНрдпрд╛ project рдЪреНрдпрд╛ dependency map рдЪреЗ model рдЖрд╣реЗ: рдкреНрд░рддреНрдпреЗрдХ suite
рдЪреНрдпрд╛ tests рдЪреА рд╕рдВрдЦреНрдпрд╛ рдЖрдгрд┐ рддреЛ code рдЪреЗ рдХреЛрдгрддреЗ рднрд╛рдЧ рдЪрд╛рд▓рд╡рддреЛ; select_tests(changed) рдХреЛрдгрддреНрдпрд╛рд╣реА рдмрджрд▓рд▓реЗрд▓реНрдпрд╛
рднрд╛рдЧрд╛рд▓рд╛ рд╕реНрдкрд░реНрд╢ рдХрд░рдгрд╛рд░реЗ suites, рддреНрдпрд╛рдВрдЪреНрдпрд╛ tests рдЪреА рд╕рдВрдЦреНрдпрд╛ рдЖрдгрд┐ рдПрдХреВрдг рд╕рдВрдЦреНрдпрд╛ рдкрд░рдд рджреЗрддреЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 exam/demo.py ci
python3 - <<'EOF'
from exam import lab
for f in (lab.grace_v0, lab.grace_v1, lab.grace_v2):
print(f.__name__, [("тЬЕ" if ok else "тЭМ") for _, ok in lab.run_grace(f)])
for changed in ({"store"}, {"report_card"}, {"grade", "attendance"}):
picked, n, total = lab.select_tests(changed)
print(f"changed {sorted(changed)} тЖТ {n}/{total} tests from {len(picked)} suites")
EOF
python3 -m unittest discover -s exam/suites -t . 2>&1 | tail -1
python3 exam/demo.py
python3 exam/test_exam.py
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
ci рд╣реЗ рдЫрд╛рдкрддреЗ:
RED (test first, no code) тЖТ 0/5 pass
GREEN (simplest code) тЖТ 5/5 pass
REFACTOR (name the rule) тЖТ 5/5 pass
тФАтФА test selection: a change to the attendance client
runs 3 of 6 suites, 28 of 105 tests: unit/test_attendance, contract/test_attendance_pact, e2e/test_report_flow
a change to grade() runs 69 of 105 tests ┬╖ merging to main still runs all 105
рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:
grace_v0 ['тЭМ', 'тЭМ', 'тЭМ', 'тЭМ', 'тЭМ']
grace_v1 ['тЬЕ', 'тЬЕ', 'тЬЕ', 'тЬЕ', 'тЬЕ']
grace_v2 ['тЬЕ', 'тЬЕ', 'тЬЕ', 'тЬЕ', 'тЬЕ']
changed ['store'] тЖТ 16/105 tests from 2 suites
changed ['report_card'] тЖТ 29/105 tests from 2 suites
changed ['attendance', 'grade'] тЖТ 93/105 tests from 5 suites
unittest discover OK рдиреЗ рд╕рдВрдкрддреЗ, рдкреВрд░реНрдг demo тЬЕ done тАФ every paper marked рдиреЗ, рдЖрдгрд┐ checks
12/12 passed рдиреЗ.
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
Red рдЖрдзреА рдЖрд▓реЗ рдЖрдгрд┐ рддреЗ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ рдард░рд▓реЗ: рдХреЛрдгрддрд╛рд╣реА code рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рдпреЗрдгреНрдпрд╛рдЖрдзреА рдкрд╛рдЪрд╣реА рдкреНрд░рд╢реНрди fail рдЭрд╛рд▓реЗ,
рдореНрд╣рдгрдЬреЗ рддреЗ fail рд╣реЛрдК рд╢рдХрддрд╛рдд. Refactor рдиреЗ code рдмрджрд▓рд▓рд╛ рдкрдг рдирд┐рдХрд╛рд▓ рдирд╛рд╣реА тАФ green suite рдпрд╛рдЪрд╕рд╛рдареА рдЕрд╕рддреЛ.
Selection рдиреЗ store рдордзрд▓реНрдпрд╛ рдмрджрд▓рд╛рд╕рд╛рдареА 105 рдкреИрдХреА рдлрдХреНрдд 16 tests рдареЗрд╡рд▓реНрдпрд╛, рдкрдг grade рдЖрдгрд┐
attendance рд▓рд╛ рд╕реНрдкрд░реНрд╢ рдХрд░рдгрд╛рд▒реНрдпрд╛ рдмрджрд▓рд╛рд▓рд╛ 93 рд▓рд╛рдЧрд▓реНрдпрд╛ тАФ рдмрджрд▓ рдЫреЛрдЯреЗ рдЕрд╕рддреАрд▓ рдЖрдгрд┐ dependency map
рдкреНрд░рд╛рдорд╛рдгрд┐рдХ рдЕрд╕реЗрд▓ рддреЗрд╡реНрд╣рд╛ selection рд╕рд░реНрд╡рд╛рдд рдЬрд╛рд╕реНрдд рд╡рд╛рдЪрд╡рддреЗ. E2e suite рдкреНрд░рддреНрдпреЗрдХ рдмрджрд▓рд╛рд╕рд╛рдареА рдирд┐рд╡рдбрд▓рд╛ рдЧреЗрд▓рд╛,
рдХрд╛рд░рдг рддреЛ рд╕рдЧрд│реНрдпрд╛рд▓рд╛рдЪ рд╕реНрдкрд░реНрд╢ рдХрд░рддреЛ.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- рдЖрдзреА code рд▓рд┐рд╣рд┐рдгреЗ рдЖрдгрд┐ "TDD" tests рдирдВрддрд░, рддреНрдпрд╛рдЪреНрдпрд╛ output рд╡рд░реВрди copy рдХрд░реВрди
- TDD рдЪреНрдпрд╛ рдореЛрдареНрдпрд╛ рдкрд╛рдпрд▒реНрдпрд╛ тАФ рдПрдХрджрдо рджрд╣рд╛ tests, рдордЧ рддрд╛рд╕рднрд░ red
- refactor рд╡рдЧрд│рдгреЗ, рддреНрдпрд╛рдореБрд│реЗ code рдХрд╛рдпрдордЪрд╛ "рд╕рд░реНрд╡рд╛рдд рд╕рд╛рдзреА рдЧреЛрд╖реНрдЯ"рдЪ рд░рд╛рд╣рддреЛ
- рд╕рд░реНрд╡рд╛рдд рд╣рд│реВ tests рдЖрдзреА рдЪрд╛рд▓рд╡рдгрд╛рд░реЗ, рдХрд┐рдВрд╡рд╛ рдкрд╣рд┐рд▓реНрдпрд╛ red рдирдВрддрд░рд╣реА рдкреБрдвреЗ рдЪрд╛рд▓реВ рд░рд╛рд╣рдгрд╛рд░реЗ CI
- рдХреБрдареЗрд╣реА рдкреВрд░реНрдг run рдирд╕рд▓реЗрд▓реЗ test selection, рддреНрдпрд╛рдореБрд│реЗ рдЪреБрдХреАрдЪрд╛ dependency map рдПрдЦрд╛рджреА рдореЛрдбрддреЛрдб рд▓рдкрд╡рддреЛ
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
рдЦрд▒реНрдпрд╛ project рдордзреНрдпреЗ тАФ рдПрдХ GitHub Actions workflow, .github/workflows/tests.yml, рдЬреЗ рдпрд╛ repo
рдЪреНрдпрд╛ checks рдкреНрд░рддреНрдпреЗрдХ push рдЖрдгрд┐ pull request рд╡рд░, рджреЛрди Python versions рд╡рд░ рдЪрд╛рд▓рд╡рддреЗ:
name: tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.12"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- run: python3 exam/test_exam.py
- run: python3 -m unittest discover -s exam/suites -t .
- run: python3 exam/demo.py > out.txt && diff out.txt demo-output.txt
pytest рд╕реЛрдмрдд рд░реЛрдЬрдЪреНрдпрд╛ рд╡рд╛рдкрд░рд╛рддрд▓реЗ рд╡реЗрдЧ рд╡рд╛рдврд╡рдгрд╛рд░реЗ рдЙрдкрд╛рдп:
pytest -x --ff # stop at the first failure, run last-failed tests first
pytest -n auto # pytest-xdist: one worker per CPU core
pytest --testmon # pytest-testmon: only tests affected by the changed code
рдордЧ test job рд▓рд╛ main branch рд╡рд░ required status check рдмрдирд╡рд╛, рдореНрд╣рдгрдЬреЗ рд▓рд╛рд▓ suite merge рдЕрдбрд╡реЗрд▓.
CI/CD рд╢рд╛рд│рд╛ рдпрд╛рднреЛрд╡рддреА рдкреВрд░реНрдг pipelines рдмрд╛рдВрдзрддреЗ.
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: push рдкрд╛рд╕реВрди green рдХрд┐рдВрд╡рд╛ red рдЙрддреНрддрд░ рдорд┐рд│реЗрдкрд░реНрдпрдВрддрдЪрд╛ рд╡реЗрд│ рдореЛрдЬрд╛. рджрд╣рд╛ рдорд┐рдирд┐рдЯрд╛рдВрдкреЗрдХреНрд╖рд╛ рдХрдореА рдЕрд╕реЗрд▓ рддрд░ рд▓реЛрдХ рддреНрдпрд╛рдЪреА рд╡рд╛рдЯ рдкрд╛рд╣рддрд╛рдд; рддреАрд╕рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдЕрд╕реЗрд▓ рддрд░ рд╡рд╛рдЯ рдкрд╛рд╣рдгреЗ рдерд╛рдВрдмрд╡рддрд╛рдд. рд╡реЗрдЧрд╡рд╛рди рдерд░ рд╡реЗрдЧрд╡рд╛рдирдЪ рдареЗрд╡рд╛, рдЬрдореЗрд▓ рддреЗ select рдХрд░рд╛, рдЖрдгрд┐ main рдЪреНрдпрд╛ рдЖрдзреА рд╕рдЧрд│реЗ рдЪрд╛рд▓рд╡рд╛.
ЁЯОУ рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╢реНрдирдкрддреНрд░рд┐рдХрд╛ рддрдкрд╛рд╕рд▓реА
рдЙрд╢рд┐рд░рд╛ рд╕рд╛рдкрдбрд▓реЗрд▓рд╛ bug рдЬрд╛рд╕реНрдд рдорд╣рд╛рдЧ рдкрдбрддреЛ, рдЖрдгрд┐ рд╕реЛрдкреЗ рдкреНрд░рд╢реНрди рддреЛ рдЪреБрдХрд╡рддрд╛рдд тЖТ arrange, act, assert, рдПрдХрд╛ рд╡реЗрд│реА рдПрдХ рдкреНрд░рд╢реНрди тЖТ рдХрдбрд╛ 34.5 рд╡рд░рдЪрд╛ bug рд╢реЛрдзрддрд╛рдд тЖТ рдирд╡реНрдпрд╛ рдЙрддреНрддрд░рдкрддреНрд░рд┐рдХрд╛ рдкреНрд░рд╢реНрдирд╛рдВрдирд╛ рд╕реНрд╡рддрдВрддреНрд░ рдареЗрд╡рддрд╛рдд тЖТ рдмрджрд▓реА рдкрд░реАрдХреНрд╖рдХ рдЬреЗ рдЪрд╛рд▓рд╡рддрд╛ рдпреЗрдд рдирд╛рд╣реА рддреНрдпрд╛рдЪреА рдЬрд╛рдЧрд╛ рдШреЗрддрд╛рдд тАФ рдкрдг рдЦреЛрдЯреЗ рдмреЛрд▓реВ рд╢рдХрддрд╛рдд тЖТ рдЦрд░рд╛ database 67.5 рдРрд╡рдЬреА 67 рд╢реЛрдзрддреЛ тЖТ contract рдирд╛рд╡-рдмрджрд▓ ship рд╣реЛрдгреНрдпрд╛рдЖрдзреАрдЪ рдерд╛рдВрдмрд╡рддреЛ тЖТ end-to-end рджрд┐рд╡рд╕ рдереЛрдбреЗ, рдЫреЛрдЯреЗ рдкреНрд░рд╢реНрди рдЦреВрдк тЖТ рдирд┐рдпрдо рдЕрдзрд┐рдХ seed рдЕрдзрд┐рдХ shrinking рд╕реНрд╡рддрдГрд╣реВрди 34.5 рд╢реЛрдзрддрд╛рдд тЖТ mutants рджрд╛рдЦрд╡рддрд╛рдд рдХреА 100% coverage рдиреЗ рдХрд╛рдп рдХрдзреАрдЪ рддрдкрд╛рд╕рд▓реЗ рдирд╛рд╣реА тЖТ рдбреБрдЧрдбреБрдЧрдгрд╛рд░реЗ рдШрдбреНрдпрд╛рд│ рдкрдХреНрдХреЗ рдХреЗрд▓реЗ рдЬрд╛рддреЗ тЖТ рдЖрдгрд┐ CI рдкреНрд░рддреНрдпреЗрдХ рдмрджрд▓рд╛рд╡рд░ рдпреЛрдЧреНрдп рдкреНрд░рд╢реНрди рд╡рд┐рдЪрд╛рд░рддреЗ. рддреБрдореНрд╣реА рдлрдХреНрдд testing рд╢рд┐рдХрд▓рд╛ рдирд╛рд╣реАрдд тАФ рдЖрддрд╛ рддреБрдореНрд╣реА рдХреЛрдгрддрд╛рд╣реА test suite рдкрд╛рд╣реВрди рд╡рд┐рдЪрд╛рд░реВ рд╢рдХрддрд╛: рдХреЛрдгрддреЗ рдкреНрд░рд╢реНрди рд░рд╛рд╣рд┐рд▓реЗ рдЖрд╣реЗрдд, рдХреЛрдгрддреА рдЙрддреНрддрд░реЗ рдЕрдВрджрд╛рдЬ рдЖрд╣реЗрдд, рдЖрдгрд┐ рдХреЛрдгрддреА рдШрдбреНрдпрд╛рд│реЗ рдбреБрдЧрдбреБрдЧрддрд╛рдд? ЁЯУЭЁЯзмЁЯОУ
тПня╕П рдкреБрдвреЗ
рдЗрддрд░ рд╢рд╛рд│рд╛. CI/CD рд╢рд╛рд│рд╛ рдпрд╛ tests рдЦрд▒реНрдпрд╛ pipelines рдордзреНрдпреЗ рдЪрд╛рд▓рд╡рддреЗ; API рд╢рд╛рд│рд╛ contracts design рдХрд░рддреЗ; Database рд╢рд╛рд│рд╛ marks book рдордзреНрдпреЗ рдЕрдзрд┐рдХ рдЦреЛрд▓рд╡рд░ рдЬрд╛рддреЗ; Observability рд╢рд╛рд│рд╛ tests рдЬреЗ рдкрд╛рд╣реВ рд╢рдХрдд рдирд╛рд╣реАрдд рддреЗ рдкрд╛рд╣рддреЗ; рд╢рд╛рд│рд╛ portal рд╡рд░ рдмрд╛рдХреА рд╕рдЧрд│реЗ рдЖрд╣реЗ.
git checkout main
python3 exam/demo.py # one last run, for fun