Rozdział 23 · Część V · Sprawdzamy i automatyzujemy
Sprawdzamy wyszukiwanie duplikatów
Puste pliki i wielomegabajtowy plik sprawdzają dwa przypadki, które łatwo przeoczyć w zwykłym teście.
SafeSort · Część 5 z 6Testy i CI
Testy dla find_duplicates() nie tylko „typowe”
tests/test_duplicates.py
def test_identical_content_files_are_grouped(tmp_path):
a = tmp_path / "notes.txt"
b = tmp_path / "copy_of_notes.txt"
a.write_text(„ten sam tekst”)
b.write_text(„ten sam tekst”)
groups = find_duplicates(scan(tmp_path, Config()))
assert len(groups) == 1
assert len(groups[0].files) == 2
def test_empty_files_are_duplicates_of_each_other(tmp_path):
(tmp_path / "a.txt").write_text("")
(tmp_path / "b.txt").write_text("")
groups = find_duplicates(scan(tmp_path, Config()))
assert len(groups) == 1
assert groups[0].size == 0
Wynik i sposób czytania są sprawdzane osobno
plik większy niż jeden blok i poprawny digest jedynie dowodzą wyniku funkcji. Taki test nie obserwuje wywołań
read(): Implementacja mogłaby odczytać cały plik naraz i nadal zwracać ten sam SHA-256. bounded reads kontraktu jest sprawdzany przez osobny instrumented reader.tests/test_duplicates.py
def test_sha256_large_file_has_correct_result(tmp_path):
data = b"x" * (5 * 1024 * 1024) # 5 MB — więcej niż jeden blok odczytu
path = tmp_path / "bolshoj_fajl.bin"
path.write_bytes(data)
assert sha256_file(path) == hashlib.sha256(data).hexdigest()
tests/test_duplicates.py: interaction test
class RecordingReader(io.BytesIO):
def __init__(self, data: bytes) -> None:
super().__init__(data)
self.requested_sizes = []
def read(self, size: int = -1) -> bytes:
self.requested_sizes.append(size)
return super().read(size)
def test_sha256_stream_uses_multiple_bounded_reads():
reader = RecordingReader(b"abcdefghij")
digest = sha256_stream(reader, chunk_size=4)
assert digest == hashlib.sha256(b"abcdefghij").hexdigest()
assert reader.requested_sizes == [4, 4, 4, 4]
assert max(reader.requested_sizes) == 4
Pierwszym testem jest result test (black-box): sprawdza,
co wróciło.
Drugi sprawdza interaction/implementation contract: zależność otrzymała kilka
ograniczonych read(4). Mały strumień nagrania
Jest to obserwowane bez silnej infrastruktury mocking-.
Praktyka: Testy plików duplikatów i pustych
Interaktywny Laptop w przeglądarce: Python 3.14 przez Pyodide, bez instalacji
Oficjalna dokumentacja