ЁЯзСтАНЁЯПл рдзрдбрд╛ 05 тАФ Test doubles: рдмрджрд▓реА рдкрд░реАрдХреНрд╖рдХ
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 05 ┬╖ рдорд╛рдЧреЗ: lesson-04-fixtures ┬╖ рдкреБрдвреЗ: lesson-06-integration
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ04, рдЖрдгрд┐ test doubles: unit test рдиреЗ рдЦрд▒реНрдпрд╛ рд╕реНрд╡рд░реВрдкрд╛рдд рд╡рд╛рдкрд░реВ рдирдпреЗрдд рдЕрд╢рд╛ рднрд╛рдЧрд╛рдВрдЪреНрдпрд╛ рдЬрд╛рдЧреА
рд╡рд╛рдкрд░рд▓реЗрд▓реЗ рдкрд░реНрдпрд╛рдп. exam/grades.py рдордзрд▓рд╛ AttendanceClient attendance
service рд▓рд╛ (рджреБрд╕рд░рд╛ server) рд╡рд┐рдЪрд╛рд░рддреЛ рдХреА рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдХрд┐рддреА рджрд┐рд╡рд╕ рдЖрд▓реА. Tests рддреНрдпрд╛ service рдЪреНрдпрд╛ рдЬрд╛рдЧреА
stub, fake, spy рдХрд┐рдВрд╡рд╛ mock рд╡рд╛рдкрд░рддрд╛рдд тАФ рдЖрдгрд┐ over-mocking рдореБрд│реЗ test рдЪреБрдХреАрдЪреА
рдЧреЛрд╖реНрдЯ рдХреБрдареЗ рддрдкрд╛рд╕рддреЗ рддреЗ рд╢рд┐рдХрддрд╛рдд. exam/lab.py рдордзрд▓реЗ StubTransport, FakeAttendance рдЖрдгрд┐
SpyTransport, standard library рдордзрд▓реЗ unittest.mock, рдЖрдгрд┐
exam/demo.py рдордзрд▓реЗ doubles().
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдЦрд▒реНрдпрд╛ attendance рдкрд░реАрдХреНрд╖рдХ, рд╕реМ. рд░рд╛рд╡, рджреБрд╕рд▒реНрдпрд╛ рдЗрдорд╛рд░рддреАрдд рдмрд╕рддрд╛рдд. рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╢реНрдирд╛рд╕рд╛рдареА рддрд┐рдереЗ рдЪрд╛рд▓рдд рдЬрд╛рдпрд▓рд╛ рдЦреВрдк рд╡реЗрд│ рд▓рд╛рдЧрддреЛ, рдЖрдгрд┐ рдХрд╛рд╣реА рджрд┐рд╡рд╕ рддреНрдпрд╛ рд░рдЬреЗрд╡рд░ рдЕрд╕рддрд╛рдд. рдореНрд╣рдгреВрди рдХрддрд░рд┐рдирд╛ рдмрджрд▓реА рд╡рд╛рдкрд░рддреЗ. ЁЯзСтАНЁЯПл
- Stub рдореНрд╣рдгрдЬреЗ рдПрдХрдЪ рдХрд╛рд░реНрдб рдЕрд╕рд▓реЗрд▓реА рдорджрддрдиреАрд╕: "200 рдкреИрдХреА 172 рджрд┐рд╡рд╕". рддреБрдореНрд╣реА рдХрд╛рд╣реАрд╣реА рд╡рд┐рдЪрд╛рд░рд╛, рддреА рддреЗрдЪ рдХрд╛рд░реНрдб рджрд╛рдЦрд╡рддреЗ. "рдпрд╛ рдЙрддреНрддрд░рд╛рдЪреЗ code рдХрд╛рдп рдХрд░рддреЛ?" рдпрд╛рд╕рд╛рдареА рдЙрдкрдпреЛрдЧреА.
- Fake рдореНрд╣рдгрдЬреЗ рд╡рд╣реАрдд рдПрдХ рдЫреЛрдЯреА, рдЪрд╛рд▓рдгрд╛рд░реА рдиреЛрдВрджрд╡рд╣реА рдЕрд╕рд▓реЗрд▓реА рдорджрддрдиреАрд╕: рддреБрдореНрд╣реА рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рдЬреЛрдбреВ рд╢рдХрддрд╛ рдЖрдгрд┐ рд╢реЛрдзреВ рд╢рдХрддрд╛. рдЦрд░реА рдиреЛрдВрджрд╡рд╣реА рдирд╛рд╣реА, рдкрдг рддрд╢реАрдЪ рд╡рд╛рдЧрддреЗ.
- Spy рдЦрд▒реНрдпрд╛ (рдХрд┐рдВрд╡рд╛ fake) рдкрд░реАрдХреНрд╖рдХрд╛рдВрдЪреНрдпрд╛ рд╢реЗрдЬрд╛рд░реА рдЙрднреА рд░рд╛рд╣рддреЗ рдЖрдгрд┐ рддреНрдпрд╛рдВрдирд╛ рд╡рд┐рдЪрд╛рд░рд▓реЗрд▓рд╛ рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╢реНрди рд▓рд┐рд╣реВрди рдареЗрд╡рддреЗ.
- Mock рдореНрд╣рдгрдЬреЗ рдЕрд╢реА рдорджрддрдиреАрд╕ рдЬрд┐рд▓рд╛ рдХреЛрдгрддрд╛ рдкреНрд░рд╢реНрди рдпреЗрдгрд╛рд░ рд╣реЗ рдЖрдзреАрдЪ рд╕рд╛рдВрдЧрд┐рддрд▓реЗрд▓реЗ рдЕрд╕рддреЗ, рдЖрдгрд┐ рд╡реЗрдЧрд│рд╛ рдкреНрд░рд╢реНрди рдЖрд▓рд╛ рддрд░ рддреА рддрдХреНрд░рд╛рд░ рдХрд░рддреЗ.
рдордЧ рджреАрдкрд┐рдХрд╛ рдЙрддреНрддрд░ рди рдмрджрд▓рддрд╛ рдкреНрд░рд╢реНрдирд╛рдЪреЗ рд╢рдмреНрдж рдмрджрд▓рддреЗ ("term 1 рд╕рд╛рдареА, рдХреГрдкрдпрд╛"). Fake рддрд░реАрд╣реА рдЙрддреНрддрд░ рджреЗрддреЗ: test pass. тЬЕ Mock рд▓рд╛ рдЬреБрдиреЗ рд╢рдмреНрдж рдЕрдкреЗрдХреНрд╖рд┐рдд рд╣реЛрддреЗ: test fail. тЭМ Mock code рдиреЗ рдХрд╕реЗ рд╡рд┐рдЪрд╛рд░рд▓реЗ рддреЗ рддрдкрд╛рд╕рдд рд╣реЛрддреЗ, рддреНрдпрд╛рдиреЗ рдХрд╛рдп рдирд┐рд╖реНрдХрд░реНрд╖ рдХрд╛рдврд▓рд╛ рддреЗ рдирд╛рд╣реА.
рдЖрдгрд┐ рдПрдХреЗ рджрд┐рд╡рд╢реА stub рдЪреБрдХреАрдЪреНрдпрд╛ рд╢реАрд░реНрд╖рдХрд╛рдЪреЗ рдХрд╛рд░реНрдб рджрд╛рдЦрд╡рддреЗ. рдЦрд▒реНрдпрд╛ рд╕реМ. рд░рд╛рд╡ рдХрдзреАрдЪ "present" рд▓рд┐рд╣реАрдд рдирд╛рд╣реАрдд тАФ рддреНрдпрд╛ "days_present" рд▓рд┐рд╣рд┐рддрд╛рдд. Test pass рдЭрд╛рд▓реА; рдЦрд░реА рд╢рд╛рд│рд╛ рдореЛрдбрддреЗ. ЁЯШм
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
c["ЁЯУЗ AttendanceClient<br/>eligible if at least 75%"] --> t{"transport"}
t -->|"production"| real["ЁЯПв real attendance service"]
t -->|"stub"| s["canned 172/200 тЖТ 86.0%"]
t -->|"fake"| f["working dict<br/>42: 86.0% ┬╖ 7: 70.0%"]
t -->|"spy"| sp["records calls<br/>/attendance/42"]
t -->|"mock"| m["expects exact call<br/>fails on ?term=1"]
ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/testing/lesson-diagrams.html#l05
тЭУ рдХрд╛рдп
рд╣реА рдирд╛рд╡реЗ Gerard Meszaros рдпрд╛рдВрдЪреНрдпрд╛ xUnit Test Patterns (2007) рдордзреВрди рдЖрд▓реА рдЖрд╣реЗрдд; Martin Fowler рдпрд╛рдВрдЪрд╛ рдирд┐рдмрдВрдз Mocks Aren't Stubs рд╣рд╛ рдлрд░рдХ рдЫрд╛рди рд╕рдордЬрд╛рд╡рддреЛ.
- Test double тАФ test рдордзреНрдпреЗ рдЦрд▒реНрдпрд╛ object рдЪреНрдпрд╛ рдЬрд╛рдЧреА рдЙрднрд╛ рд░рд╛рд╣рдгрд╛рд░рд╛ рдХреЛрдгрддрд╛рд╣реА object (рдЪрд┐рддреНрд░рдкрдЯрд╛рддрд▓реНрдпрд╛ stunt double рд╕рд╛рд░рдЦрд╛).
- Dummy тАФ рдлрдХреНрдд parameter рднрд░рдгреНрдпрд╛рд╕рд╛рдареА рджрд┐рд▓реЗрд▓рд╛; рдХрдзреАрдЪ рд╡рд╛рдкрд░рд▓рд╛ рдЬрд╛рдд рдирд╛рд╣реА.
- Stub тАФ рдард░рд▓реЗрд▓реА рдЙрддреНрддрд░реЗ рдкрд░рдд рджреЗрддреЛ. Test рд╣реЛрдгрд╛рд▒реНрдпрд╛ code рд▓рд╛ рдПрдЦрд╛рджреНрдпрд╛ рд╕реНрдерд┐рддреАрдд рдЖрдгрдгреНрдпрд╛рд╕рд╛рдареА рд╡рд╛рдкрд░рддрд╛рдд: "service рдореНрд╣рдгрддреЗ 404", "service рдореНрд╣рдгрддреЗ 503".
- Fake тАФ рдЪрд╛рд▓рдгрд╛рд░реА, рд╕реЛрдкреА рдЕрдВрдорд▓рдмрдЬрд╛рд╡рдгреА: in-memory database, dict рд╡рд░ рдЖрдзрд╛рд░рд┐рдд service. рдЦрд░реЗ рд╡рд░реНрддрди, рдкрдг production рд╕рд╛рдареА рддрдпрд╛рд░ рдирд╛рд╣реА.
- Spy тАФ рддреНрдпрд╛рд▓рд╛ рдХрд╕реЗ рдмреЛрд▓рд╡рд▓реЗ рдЧреЗрд▓реЗ рддреЗ рдиреЛрдВрджрд╡рддреЛ, рдореНрд╣рдгрдЬреЗ test рдирдВрддрд░ рддрдкрд╛рд╕реВ рд╢рдХрддреЗ.
- Mock тАФ calls рдмрджреНрджрд▓рдЪреНрдпрд╛ рдЕрдкреЗрдХреНрд╖рд╛ рдЖрдзреАрдЪ program рдХреЗрд▓реЗрд▓реНрдпрд╛, рдЖрдгрд┐ рддреЛ рддреНрдпрд╛ рдкрдбрддрд╛рд│рддреЛ.
Python рдордзреНрдпреЗ,
unittest.mock.Mockрд╣рд╛ рд▓рд╡рдЪрд┐рдХ object рдЖрд╣реЗ рдЬреЛ stub рд╕рд╛рд░рдЦрд╛ рд╡рд╛рдЧреВ рд╢рдХрддреЛ (return_value,side_effect) рдЖрдгрд┐ spy рд╕рд╛рд░рдЦреЗ calls рдиреЛрдВрджрд╡рддреЛ (assert_called_once_with). - State verification рд╡рд┐рд░реБрджреНрдз behaviour verification тАФ рдирд┐рдХрд╛рд▓ рддрдкрд╛рд╕рд╛ (рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА
eligible рдЖрд╣реЗ), рдХрд┐рдВрд╡рд╛ calls рддрдкрд╛рд╕рд╛ (client рдиреЗ
/attendance/42рдмреЛрд▓рд╡рд▓реЗ). State verification refactoring рдордзреНрдпреЗ рдЬрд╛рд╕реНрдд рдЪрд╛рдВрдЧрд▓реЗ рдЯрд┐рдХрддреЗ. - Over-mocking тАФ рдЗрддрдХреЗ doubles, рдЗрддрдХреНрдпрд╛ рдиреЗрдордХреЗрдкрдгрд╛рдиреЗ рддрдкрд╛рд╕рд▓реЗрд▓реЗ, рдХреА test code рдУрд│-рди-рдУрд│ рдкреБрдиреНрд╣рд╛ рд╕рд╛рдВрдЧрддреЗ. Code refactor рдХреЗрд▓рд╛ рдХреА рддреА рдореЛрдбрддреЗ, рдЖрдгрд┐ рдЦрд░рд╛ рд╕рд╣рдХрд╛рд░реА рдмрджрд▓рд▓рд╛ рддрд░реА рддреА pass рд╣реЛрддреЗ.
- Dependency injection тАФ client рдЖрдкрд▓рд╛
transportparameter рдореНрд╣рдгреВрди рдШреЗрддреЛ, рдореНрд╣рдгрдЬреЗ test double рджреЗрдК рд╢рдХрддреЗ. рдЖрддрдЪ рд╕реНрд╡рддрдГрдЪреЗ HTTP connection рддрдпрд╛рд░ рдХрд░рдгрд╛рд░рд╛ code test рдХрд░рд╛рдпрд▓рд╛ рдХрдареАрдг рдЕрд╕рддреЛ.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг unit test рд╡реЗрдЧрд╡рд╛рди рдЖрдгрд┐ рдЦрд╛рддреНрд░реАрд╢реАрд░ рдЕрд╕рд╛рдпрд▓рд╛ рд╣рд╡реА, рдЖрдгрд┐ рдЦрд░реА service рджреЛрдиреНрд╣реАрдкреИрдХреА рдХрд╛рд╣реАрдЪ рдирд╛рд╣реА: рддреА network рд╡рд░ рдЖрд╣реЗ (distributed-systems рд╢рд╛рд│реЗрдЪрд╛ рдзрдбрд╛ 01), рддреА рдмрдВрдж рдЕрд╕реВ рд╢рдХрддреЗ, рдЖрдгрд┐ рддрд┐рдЪреНрдпрд╛рдХрдбреЗ рддреБрдордЪреНрдпрд╛ рдирд┐рдпрдВрддреНрд░рдгрд╛рдд рдирд╕рд▓реЗрд▓рд╛ data рдЕрд╕рддреЛ. Doubles рдореБрд│реЗ "503 рд╡рд░ рдХрд╛рдп рд╣реЛрддреЗ?" рд╣реЗ рддреБрдореНрд╣реА рдПрдХрд╛ millisecond рдордзреНрдпреЗ рд╡рд┐рдЪрд╛рд░реВ рд╢рдХрддрд╛. рдкрдг рдкреНрд░рддреНрдпреЗрдХ double рд╣рд╛ рдЦрд▒реНрдпрд╛ рдЧреЛрд╖реНрдЯреАрдмрджреНрджрд▓рдЪрд╛ рдПрдХ рджрд╛рд╡рд╛ рдЖрд╣реЗ. рдХреЛрдгреАрдЪ рди рддрдкрд╛рд╕рд▓реЗрд▓рд╛ рджрд╛рд╡рд╛ рдЪреБрдХреАрдЪрд╛ рдЕрд╕реВ рд╢рдХрддреЛ тАФ рдзрдбрд╛ 07 рддреЛ рддрдкрд╛рд╕рддреЛ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
exam/grades.py рдордзрд▓рд╛ AttendanceClient(transport)
transport("/attendance/<id>") рдмреЛрд▓рд╡рддреЛ рдЖрдгрд┐ (status, body) рдЕрдкреЗрдХреНрд╖рд┐рдд рдзрд░рддреЛ. 404 рд╡рд░ рддреЛ StudentNotFound
рджреЗрддреЛ, 5xx рд╡рд░ AttendanceUnavailable, рдЖрдгрд┐ рдЕрдиреНрдпрдерд╛
days_present ├Ч 100 ├╖ days_total рдореЛрдЬрддреЛ, рдПрдХрд╛ рджрд╢рд╛рдВрд╢рд╛рдкрд░реНрдпрдВрдд round рдХрд░реВрди.
exam/lab.py рдордзреНрдпреЗ, StubTransport(status, body) рдиреЗрд╣рдореА рддреАрдЪ рдЬреЛрдбреА
рдкрд░рдд рджреЗрддреЛ, FakeAttendance рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреАрдВрдЪреА dict рдареЗрд╡рддреЛ рдЖрдгрд┐ рдЕрдиреЛрд│рдЦреАрдВрд╕рд╛рдареА 404 рдЙрддреНрддрд░ рджреЗрддреЛ, рдЖрдгрд┐
SpyTransport(inner) calls рдкреБрдвреЗ рдкрд╛рдард╡рддреЛ рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ path calls рдордзреНрдпреЗ рдЬреЛрдбрддреЛ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 exam/demo.py doubles
python3 - <<'EOF'
from unittest import mock
from exam.grades import AttendanceClient, StudentNotFound, AttendanceUnavailable
from exam.lab import StubTransport, FakeAttendance, SpyTransport
for status in (200, 404, 500, 503):
c = AttendanceClient(StubTransport(status, {"days_present": 150, "days_total": 200}))
try: print(f"stub says {status} тЖТ eligible {c.eligible('9')}")
except (StudentNotFound, AttendanceUnavailable) as e: print(f"stub says {status} тЖТ {type(e).__name__}")
fake = FakeAttendance().add("1", 149, 200).add("2", 150, 200)
spy = SpyTransport(fake); c = AttendanceClient(spy)
print("149/200:", c.eligible("1"), "┬╖ 150/200:", c.eligible("2"), "┬╖ calls:", spy.calls)
m = mock.Mock(side_effect=[(503, {}), (200, {"days_present": 180, "days_total": 200})])
c = AttendanceClient(m)
for _ in range(2):
try: print("mock тЖТ", c.attendance_percent("5"))
except AttendanceUnavailable: print("mock тЖТ AttendanceUnavailable")
print("mock was called", m.call_count, "times with", m.call_args_list[0])
EOF
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
doubles рдЫрд╛рдкрддреЗ:
stub (canned answer) тЖТ attendance 86.0% ┬╖ eligible True
fake (a small working one) тЖТ student 42: 86.0% ┬╖ student 7: 70.0% ┬╖ eligible False
spy (records calls) тЖТ calls ['/attendance/42']
mock (unittest.mock) тЖТ a 503 raises AttendanceUnavailable; assert_called_once_with('/attendance/42') holds
fake-based test: eligible True тЖТ passes ┬╖ mock-based test тЖТ FAILS (the mock checked HOW, not WHAT)
рддреБрдордЪрд╛ snippet рдЫрд╛рдкрддреЛ:
stub says 200 тЖТ eligible True
stub says 404 тЖТ StudentNotFound
stub says 500 тЖТ AttendanceUnavailable
stub says 503 тЖТ AttendanceUnavailable
149/200: False ┬╖ 150/200: True ┬╖ calls: ['/attendance/1', '/attendance/2']
mock тЖТ AttendanceUnavailable
mock тЖТ 90.0
mock was called 2 times with call('/attendance/5')
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
Stub рдореБрд│реЗ рддреБрдореНрд╣реА рдЪрд╛рд░ рдУрд│реАрдВрдд рдкреНрд░рддреНрдпреЗрдХ status code рдкрд╛рд╣реВ рд╢рдХрд▓рд╛рдд тАФ рдЦрд░реА service рд╣реЗ рдорд╛рдЧрдгреАрд╡рд░ рдХреНрд╡рдЪрд┐рддрдЪ
рдХрд░реЗрд▓. Fake рд▓рд╛ рдЕрд╢реА рдХрдб рд╕рд╛рдкрдбрд▓реА рдЬреА stub рд▓рд╛ рд╕рд╛рдкрдбрд▓реА рдирд╕рддреА: 200 рдкреИрдХреА 149 рджрд┐рд╡рд╕ рдореНрд╣рдгрдЬреЗ
74.5%, рдЬреЗ eligible рдирд╛рд╣реА. side_effect рдпрд╛рджреАрдореБрд│реЗ mock рдПрдХрджрд╛ fail рдЭрд╛рд▓реЗ рдЖрдгрд┐ рдордЧ
рдЙрддреНрддрд░ рджрд┐рд▓реЗ тАФ retry test рдЪрд╛ рд╣рд╛рдЪ рдЖрдХрд╛рд░. рдЖрдгрд┐ demo over-mocking рдЪреА рдХрд┐рдВрдордд рджрд╛рдЦрд╡рддреЛ: URL рдордзрд▓реНрдпрд╛
рдирд┐рд░реБрдкрджреНрд░рд╡реА рдмрджрд▓рд╛рдиреЗ mock-based test рдореЛрдбрд▓реА, рддрд░ рдЪреБрдХреАрдЪреНрдпрд╛ field
рдирд╛рд╡рд╛рдВрдЪрд╛ stub рдЖрдирдВрджрд╛рдиреЗ pass рдЭрд╛рд▓рд╛ рдЖрдгрд┐ production рдордзреНрдпреЗ KeyError 'days_present' рдиреЗ crash рдЭрд╛рд▓рд╛ рдЕрд╕рддрд╛.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- рд╕рдЧрд│реНрдпрд╛рдЪреЗрдЪ mocking рдХрд░рдгреЗ, рддреБрдордЪреНрдпрд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ рд╕рд╛рдзреНрдпрд╛ objects рд╕рд╣ (рдЦрд░рд╛ object рдЪ рд╡рд╛рдкрд░рд╛)
- рдкреНрд░рддреНрдпреЗрдХ call рдЖрдгрд┐ argument рд╡рд░ assert рдХрд░рдгреЗ, рдореНрд╣рдгрдЬреЗ рдХреЛрдгрддрд╛рд╣реА refactor test рдореЛрдбрддреЛ
- рдЦрд░реА service рдХрдзреАрдЪ рджреЗрдд рдирд╛рд╣реА рдЕрд╢реА рдЙрддреНрддрд░реЗ рджреЗрдгрд╛рд░реЗ stubs (рдЪреБрдХреАрдЪреА field рдирд╛рд╡реЗ, рдЪреБрдХреАрдЪреЗ types)
- library рд▓рд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ рдЫреЛрдЯреНрдпрд╛ interface рдордзреНрдпреЗ рдЧреБрдВрдбрд╛рд│рдгреНрдпрд╛рдРрд╡рдЬреА рддрд┐рдЪреНрдпрд╛ рдЖрддрд▓реНрдпрд╛ рднрд╛рдЧрд╛рдВрдЪреЗ mocking рдХрд░рдгреЗ
- рдЪреБрдХреАрдЪреНрдпрд╛ рдирд╛рд╡рд╛рд╡рд░
mock.patchтАФ code рдЬрд┐рдереЗ рддреЗ рд╢реЛрдзрддреЛ рддрд┐рдереЗ patch рдХрд░рд╛, рдЬрд┐рдереЗ рддреЗ define рдХреЗрд▓реЗ рдЖрд╣реЗ рддрд┐рдереЗ рдирд╛рд╣реА
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
рдЦрд▒реНрдпрд╛ project рд╡рд░ тАФ unittest.mock.patch test рдЪреНрдпрд╛ рдХрд╛рд▓рд╛рд╡рдзреАрдкреБрд░рддреЗ рдПрдХ рдирд╛рд╡ рдмрджрд▓рддреЗ, рдЖрдгрд┐
autospec=True рдореБрд│реЗ double рдЦрд░реЗ function рд╕реНрд╡реАрдХрд╛рд░реВ рд╢рдХрдгрд╛рд░ рдирд╛рд╣реА рдЕрд╕реЗ calls рдирд╛рдХрд╛рд░рддреЛ:
from unittest import mock
import exam.grades
def test_report_uses_attendance():
with mock.patch.object(exam.grades.AttendanceClient, "attendance_percent",
autospec=True, return_value=80.0):
assert exam.grades.AttendanceClient(None).eligible("42") is True
autospec signature рддрдкрд╛рд╕рддреЗ, рдЙрддреНрддрд░реЗ рдирд╛рд╣реА тАФ рдЦрд▒реНрдпрд╛ service рдиреЗ field рдЪреЗ рдирд╛рд╡ рдмрджрд▓рд▓реЗ рд╣реЗ рддреЗ
рд╕рд╛рдВрдЧреВ рд╢рдХрдд рдирд╛рд╣реА. HTTP рд╕рд╛рдареА, record-and-replay рдЖрдгрд┐ stub-server рд╕рд╛рдзрдиреЗ рдорджрдд рдХрд░рддрд╛рдд:
responses рдЖрдгрд┐ respx (Python), WireMock (Java, рд╕реНрд╡рддрдВрддреНрд░ server рдореНрд╣рдгреВрдирд╣реА
рдЪрд╛рд▓рддреЗ), MSW (JavaScript). рддреБрдордЪреНрдпрд╛ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ dependencies рд╕рд╛рдареА, рдЦрд▒реНрдпрд╛ implementation рд╢реЗрдЬрд╛рд░реА
рддреБрдореНрд╣реА рд╕рд╛рдВрднрд╛рд│рд▓реЗрд▓рд╛ fake рд╡рд╛рдкрд░рд╛ рдЖрдгрд┐ рджреЛрдиреНрд╣реА рдПрдХрд╛рдЪ checks рд╡рд░ test рдХрд░рд╛.
ЁЯПн Production рдордзреНрдпреЗ рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рддреБрдордЪреНрдпрд╛ suite рдордзрд▓реНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ double рдмрджреНрджрд▓ рд╡рд┐рдЪрд╛рд░рд╛ "рдпрд╛рд▓рд╛ рдкреНрд░рд╛рдорд╛рдгрд┐рдХ рдХреЛрдг рдареЗрд╡рддреЗ?" рдЙрддреНрддрд░ "рдХреЛрдгреАрдЪ рдирд╛рд╣реА" рдЕрд╕реЗрд▓, рддрд░ рддреЛ рджреБрд╕рд▒реНрдпрд╛ team рдЪреНрдпрд╛ service рдмрджреНрджрд▓рдЪрд╛ рдЕрдВрджрд╛рдЬ рдЖрд╣реЗ. Contract tests (рдзрдбрд╛ 07) рдХрд┐рдВрд╡рд╛ integration tests рдЪрд╛ рдЫреЛрдЯрд╛ рд╕рдВрдЪ (рдзрдбрд╛ 06) рддреНрдпрд╛ рдЕрдВрджрд╛рдЬрд╛рд▓рд╛ рддрдкрд╛рд╕рдгреАрдд рдмрджрд▓рддрд╛рдд.
тПня╕П рдкреБрдвреЗ
рдзрдбрд╛ 04 рдордзрд▓рд╛ fake store рд╣рд╛ Python dict рд╣реЛрддрд╛. рдЦрд░рд╛ store SQL рдЖрд╣реЗ. Integration tests рдЦрд░рд╛ SQLite database рд╡рд╛рдкрд░рддрд╛рдд тАФ рдЖрдгрд┐ fake рд▓рд╛ рди рд╕рд╛рдкрдбрдгрд╛рд░рд╛ bug рд╢реЛрдзрддрд╛рдд.
git checkout lesson-06-integration