pytest:如何测试与项目相关的目录创建?

时间:2018-12-10 23:07:21

标签: python pytest

我正在开发一个具有以下架构的项目:

|-- 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 :(得分:2)

由于您已经考虑过提供自定义保存路径,因此,如果您不想的话,甚至不需要模拟任何内容。只需传递从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. 仅在3.6版之前的Python版本中才需要对类似路径的对象进行字符串转换。如果您使用3.6或3.7,则可以直接使用类似路径的对象,例如

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

    shutil.rmtree(lib_dir)
    
  2. 请注意,os.rename / os.renames在更改文件系统方面不易出错,例如您在本地ext4分区上写入data.json,并且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()