текст перекладу
В Частині 1 ми обговорювали ідею та мету нашого додатку, а також TDD. Ми також реалізували наші перші невдалий тести, і настав час написати фактичні тіла функцій, щоб задовольнити наші вимоги. Почнемо з перевірки порогу. Ми перевіримо, чи є переданий поріг позитивним числом:
from analyzer.errors import DirectoryNotFoundError, InvalidThresholdError
def find_large_files(directory, size_threshold):
if size_threshold < 0:
raise InvalidThresholdError(
"Поріг розміру повинен бути позитивним цілим числом."
)
Тепер, коли ми запустимо тести, ми побачимо два невдалі та один успішний тест, тобто перевірка порогу працює добре.
============================================================================ коротка інформація про результати тестів =============================================================================
FAILED tests/test_large_files.py::test_find_large_files - AssertionError: assert None == ['/path/to/file2.jpg']
FAILED tests/test_large_files.py::test_find_large_files_directory_not_found - Не вдалося: НЕ ВИКИНУВАЛО
========================================================================== 2 невдалі, 1 успішний в 0.16с ===========================================================================
Це добре. Далі ми подбаємо про DirectoryNotFoundError
, для чого нам потрібно імпортувати модуль os
, щоб перевірити, чи є переданий шлях дійсним/існуючим каталогом.
import os
from analyzer.errors import DirectoryNotFoundError, InvalidThresholdError
def find_large_files(directory, size_threshold):
if not os.path.isdir(directory):
raise DirectoryNotFoundError(
f"Вказаний каталог '{directory}' не існує або не є каталогом."
)
if size_threshold < 0:
raise InvalidThresholdError(
"Поріг розміру повинен бути позитивним цілим числом."
)
У тесті для успішного випадку не буде хорошою ідеєю жорстко прописувати існуючі каталоги та імена файлів, оскільки вони можуть змінюватися і варіюватися залежно від машини, на якій запускається інструмент, тому ми змокуємо значення, яке повертається os.path.isdir
, щоб воно завжди було True. Для недійсних випадків це не потрібно робити, оскільки invalid/directory
сам по собі є недійсним шляхом.
from unittest.mock import patch
import pytest
from file_system_analyzer.analyzer.large_files import find_large_files
from file_system_analyzer.analyzer.errors import DirectoryNotFoundError, InvalidThresholdError
@patch('file_system_analyzer.analyzer.large_files.os.path.isdir')
def test_find_large_files(mock_isdir):
mock_isdir.return_value = True
result = find_large_files('/path/to/directory', 1000000)
mock_isdir.assert_called_with('/path/to/directory')
assert result == ['/path/to/file2.jpg']
def test_find_large_files_directory_not_found():
with pytest.raises(DirectoryNotFoundError):
find_large_files('/invalid/directory', 1000000)
@patch('file_system_analyzer.analyzer.large_files.os.path.isdir')
def test_find_large_files_invalid_threshold(mock_isdir):
mock_isdir.return_value = True
with pytest.raises(InvalidThresholdError):
find_large_files('/path/to/directory', -100)
Тепер лише один тест не пройде, що буде помилкою твердження, оскільки функція все ще не повертає нічого.
текст перекладу
Але відповідні/очікувані помилки повинні бути викинуті:
============================================================================ коротка інформація про результати тестів =============================================================================
FAILED tests/test_large_files.py::test_find_large_files - AssertionError: assert None == ['/path/to/file2.jpg']
========================================================================== 1 невдалий, 2 успішних за 0.11с ===========================================================================
Щоб останній тест пройшов, нам потрібна допоміжна функція для рекурсивного обходу каталогу та повернення шляхів до файлів:
# file_system_analyzer/analyzer/traversal.py
import os
def traverse_directory(directory):
for root, dirs, files in os.walk(directory):
for file in files:
yield os.path.join(root, file)
Далі ми імпортуємо її та перевіряємо, чи є файли в заданому шляху більшими за поріг, а потім повертаємо список знайдених файлів.
import os
from analyzer.traversal import traverse_directory
from analyzer.errors import DirectoryNotFoundError, InvalidThresholdError
def find_large_files(directory, size_threshold):
if not os.path.isdir(directory):
raise DirectoryNotFoundError(
f"Вказаний каталог '{directory}' не існує або не є каталогом."
)
if size_threshold < 0:
raise InvalidThresholdError(
"Поріг розміру повинен бути позитивним цілим числом."
)
large_files = []
for file_path in traverse_directory(directory):
if os.path.getsize(file_path) > size_threshold:
large_files.append(file_path)
return large_files
Остаточна тестова система виглядатиме ось так після додавання моків для traverse_directory
та os.path.getsize
:
# tests/test_large_files.py
from unittest.mock import patch
import pytest
from file_system_analyzer.analyzer.large_files import find_large_files
from file_system_analyzer.analyzer.errors import DirectoryNotFoundError, InvalidThresholdError
@patch('file_system_analyzer.analyzer.large_files.os.path.getsize')
@patch('file_system_analyzer.analyzer.large_files.traverse_directory')
@patch('file_system_analyzer.analyzer.large_files.os.path.isdir')
def test_find_large_files(mock_isdir, mock_traverse_directory, mock_getsize):
mock_isdir.return_value = True
mock_traverse_directory.return_value = ['/path/to/file1.txt', '/path/to/file2.jpg']
mock_getsize.side_effect = [500000, 2000000]
result = find_large_files('/path/to/directory', 1000000)
mock_isdir.assert_called_with('/path/to/directory')
assert result == ['/path/to/file2.jpg']
def test_find_large_files_directory_not_found():
with pytest.raises(DirectoryNotFoundError):
find_large_files('/invalid/directory', 1000000)
@patch('file_system_analyzer.analyzer.large_files.os.path.isdir')
def test_find_large_files_invalid_threshold(mock_isdir):
mock_isdir.return_value = True
with pytest.raises(InvalidThresholdError):
find_large_files('/path/to/directory', -100)
Врешті-решт, у логах тестів буде все зелено:
=========================== 3 успішних за 0.08с ===========================
Ось і все. Ми це зробили. Ми завершили цілий цикл TDD для частини нашого інструмента, і можемо йти вперед з іншими модулями, слідуючи тій самій логіці. Побачимось у Частині 3, де ми реалізуємо решту відсутніх частин нашої програми. А в Частині 4 ми завершимо поєднання всіх частин в один реальний CMD інструмент з його командами та зручним для користувача описом.
Перекладено з: File System Analyzer on Python with TDD step by step (Part 2)