pytest: Как протестировать создание каталога в зависимости от проекта? - PullRequest
0 голосов
/ 11 декабря 2018

Я занимаюсь разработкой проекта со следующей архитектурой:

|-- weather
|   |-- __init__.py
|   |-- weather.py
|-- library
|   |-- data.json
|-- test
|   |-- __init__.py
|   |-- test_weather.py

Я хотел бы проверить, что при выполнении сохранения создается каталог library, если он еще не существует.test_weather.py содержит:

import os
import shutil

from weather import weather

def test_library_creation():
    # Initialize.
    app = weather.WeatherApp()
    temp_data = app.get_data()
    # Library should not exist initially.
    assert not os.path.isdir('library')
    app.save(temp_data)
    # Library should exist after save.
    assert os.path.isdir('library')
    assert os.path.isfile(os.path.join('library', 'data.json'))
    # Cleanup.
    shutil.rmtree('library')

Однако в data.json могут быть сохранены некоторые данные, которые я не хочу удалять в результате выполнения этого теста.

Имеет pytest есть решение для этого случая?


РЕДАКТИРОВАТЬ:

weather.py содержит:

import os
import json

DEFAULT_SAVE_PATH = os.path.join('library', 'data.json')

class WeatherApp:
    def get_data(self):
        return dict(temperature=25, humidity=0.5)

    def save(self, data, save_path=DEFAULT_SAVE_PATH):
        with open('data.json', 'w') as jf:
            json.dump(data, jf)
        os.renames('data.json', save_path)

1 Ответ

0 голосов
/ 12 декабря 2018

Так как вы уже подумали о предоставлении собственного пути сохранения, вам даже не нужно что-либо насмехаться, если вы этого не хотите;просто передайте пользовательский путь, полученный из фиксатора tmp_path:

def test_library_creation(tmp_path):
    app = weather.WeatherApp()
    temp_data = app.get_data()
    lib_dir = tmp_path / 'library'
    # this check is somewhat redundant because pytest will ensure
    # the temp dir is created from scratch and is empty
    assert not lib_dir.is_dir()
    app.save(temp_data, save_path=str(lib_dir / 'data.json'))
    # Library should exist after save.
    assert lib_dir.is_dir()
    assert (lib_dir / 'data.json').is_file()
    shutil.rmtree(str(lib_dir))

Некоторые примечания:

  1. Преобразование строк в виде путей требуется только в Pythonверсии старше 3.6;если вы используете 3.6 или 3.7, вы можете работать непосредственно с объектами, подобными траектории, например,

    app.save(temp_data, save_path=lib_dir / 'data.json')
    

    или

    shutil.rmtree(lib_dir)
    
  2. Остерегайтесь, что os.rename / os.renames не подвержен ошибкам при изменении файловых систем, например, вы пишете data.json в локальном разделе ext4, а save_path указывает на общий ресурс CIFS, и здесь возникает ошибка.

  3. Может быть, операция переименования является избыточной?Вы можете записать данные непосредственно в save_path.Вам просто нужно убедиться, что целевой каталог существует первым, например, с помощью os.makedirs(os.path.dirname(save_path), exist_ok=True).

  4. Если утверждение не выполнено в тесте, строка shutil.rmtree(str(lib_dir)) не будет выполнена;это не страшно, так как tmp_path создается на tmpfs и будет удалена после следующей перезагрузки в любом случае.Однако, если вы хотите обработать удаление самостоятельно, я бы сделал это при разборке теста с использованием специального приспособления:

    import os
    import shutil
    import pytest
    
    from weather import weather
    
    
    @pytest.fixture
    def lib_dir(tmp_path):
        d = tmp_path / 'library'
        yield d
        shutil.rmtree(str(d))
    
    
    def test_library_creation(lib_dir):
        app = weather.WeatherApp()
        temp_data = app.get_data()
        assert not lib_dir.is_dir()
        app.save(temp_data, save_path=str(lib_dir))
        # Library should exist after save.
        assert lib_dir.is_dir()
        assert (lib_dir / 'data.json').is_file()
    

    Теперь lib_dir будет удалено независимо от того, пройден тест или нет.

  5. Если вы хотите протестировать аргументы по умолчанию (случай app.save(temp_data)), вам нужно будет установить постоянную DEFAULT_SAVE_PATH в модуле weather.С помощью приспособления monkeypatch это довольно просто:

    def test_library_creation(monkeypatch, lib_dir):
        app = weather.WeatherApp()
        temp_data = app.get_data()
        assert not lib_dir.is_dir()
        with monkeypatch.context() as m:
            m.setattr(weather, 'DEFAULT_SAVE_PATH', os.path.join(lib_dir, 'data.json'))
            app.save(temp_data)
        # Library should exist after save.
        assert lib_dir.is_dir()
        assert (lib_dir / 'data.json').is_file()
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...