текст перекладу Аналізатор файлової системи на Python з кроками TDD (Частина 2)

текст перекладу
В Частині 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)

Leave a Reply

Your email address will not be published. Required fields are marked *