Pytest系列(31) - config.cache 使用

基础介绍

官方地址:https://docs.pytest.org/en/8.0.x/reference/reference.html#config-cache

  • pytest 中,cache 是一个非常有用的功能,它允许测试会话之间持久化状态
  • 这意味着可以在一次测试运行中存储一些值,并在后续的测试运行中访问这些值

如何使用 cache

cache 对象通过 pytestFixtureRequest 对象提供,通常在一个 fixture 中获取并返回它

@fixture
def cache(request: FixtureRequest) -> Cache:
    """Return a cache object that can persist state between testing sessions.

    cache.get(key, default)
    cache.set(key, value)

    Keys must be ``/`` separated strings, where the first part is usually the
    name of your plugin or application to avoid *****es with other cache users.

    Values can be any object handled by the json stdlib module.
    """
    assert request.config.cache is not None
    return request.config.cache

image.png

  • pytest 的缓存机制是通过一个名为 .pytest_cache 的目录实现的,该目录位于项目的根目录下
  • config.cache 对象提供了一个简单的键值存储接口,允许测试代码读取和写入缓存数据
  • 一个 key 一个文件

存储和检索数据

cache 对象提供了两个主要方法:getset

  • get(key, default=None) 方法用于检索之前存储的值。如果指定的 key 不存在,则返回 default 值。
  • set(key, value) 方法用于存储值。key 应该是一个字符串,而 value 可以是任何可以被 json 标准库模块处理的对象。
# 设置缓存值
config.cache.set("key", "value")

# 获取缓存值
value = config.cache.get("key", None)  # 如果键不存在,返回 None

键建议使用 / 分隔的字符串,其中第一部分通常是你的插件或应用程序的名称,以避免与其他使用 cache 的代码冲突

示例

假设有一个测试,需要从外部API获取数据,但这个操作很耗时,可以在第一次运行测试时从API获取数据,并将其存储在 cache 中。在后续的测试运行中,可以直接从 cache 中检索数据,避免重复的API调用

def test_external_api(cache):
    # 尝试从缓存中获取数据
    data = cache.get('external_api/data', default=None)
    if data is None:
        # 如果缓存中没有数据,则从API获取并存储到缓存中
        data = fetch_data_from_external_api()  # 假设这是一个函数来获取数据
        cache.set('external_api/data', data)
    
    # 使用数据进行测试
    assert data is not None

源码解析

pytest 的缓存机制是在 _pytest/cacheprovider.py 文件中实现的

def get(self, key: str, default):
    """Return the cached value for the given key.

    If no value was yet cached or the value cannot be read, the specified
    default is returned.

    :param key:
        Must be a ``/`` separated value. Usually the first
        name is the name of your plugin or your application.
    :param default:
        The value to return in case of a cache-miss or invalid cache value.
    """
    path = self._getvaluepath(key)
    try:
        with path.open("r") as f:
            return json.load(f)
    except (ValueError, OSError):
        return default

def set(self, key: str, value: object) -> None:
    """Save value for the given key.

    :param key:
        Must be a ``/`` separated value. Usually the first
        name is the name of your plugin or your application.
    :param value:
        Must be of any combination of basic python types,
        including nested types like lists of dictionaries.
    """
    path = self._getvaluepath(key)
    try:
        if path.parent.is_dir():
            cache_dir_exists_already = True
        else:
            cache_dir_exists_already = self._cachedir.exists()
            path.parent.mkdir(exist_ok=True, parents=True)
    except OSError:
        self.warn("could not create cache path {path}", path=path, _ispytest=True)
        return
    if not cache_dir_exists_already:
        self._ensure_supporting_files()
    data = json.dumps(value, indent=2)
    try:
        f = path.open("w")
    except OSError:
        self.warn("cache could not write path {path}", path=path, _ispytest=True)
    else:
        with f:
            f.write(data)
  • 代码还是比较简单的,key 就是一个文件路径,不存在则创建,然后写入数据
  • 这些方法最终会将数据序列化为 JSON 格式
posted @ 2024-03-25 14:31  小菠萝测试笔记  阅读(1260)  评论(0)    收藏  举报