簡體   English   中英

如何在 pytest test_functions 之間重置 Python 運行時?

[英]How do I reset Python runtime between pytest test_functions?

我正在使用 pytest 來測試創建 prometheus Python 客戶端以導出指標的代碼。

在測試功能之間,prometheus 客戶端不會重置(因為它具有內部狀態),這會搞砸我的測試。

我正在尋找一種在所有測試 function 調用之前基本上獲得新的 Pyhon 運行時的方法。 這樣,prometheus 客戶端的內部 state 有望重置為 Python 運行時開始執行我的測試時的 state。

我已經嘗試過importlib.reload()但這不起作用。

如果您想使用“干凈”的 Prometheus 客戶端開始每個測試,那么我認為最好將其創建並拆除到帶有 function scope 的夾具(它實際上是默認范圍),如下所示:

@pytest.fixture(scope=function)
def prometheus_client(arg1, arg2, etc...)
#create your client here
yield client
#remove your client here

然后你使用這個夾具定義你的測試:

def test_number_one(prometheus_client):
#test body

這樣客戶端在每個測試中都是從頭開始創建的,即使測試失敗也會被刪除。

直截了當的方法:在測試前記住當前的指標值

首先,讓我展示一下我認為您應該如何在測試中使用指標(以及我如何在我的項目中這樣做)。 我沒有進行重置,而是在測試開始之前跟蹤指標值。 測試完成后,我再次收集指標並分析兩個值之間的差異。 帶有計數器的 django 視圖測試示例:

import copy
import prometheus_client
import pytest

from django.test import Client
from django.urls import reverse


def find_value(metrics, metric_name):
    return next((
        sample.value
        for metric in metrics
        for sample in metric.samples
        if sample.name == metric_name
    ), None)


@pytest.fixture
def metrics_before():
    yield copy.deepcopy(list(prometheus_client.REGISTRY.collect()))


@pytest.fixture
def client():
    return APIClient()


def test_counter_increases_by_one(client, metrics_before):
    # record the metric value before the HTTP client requests the view
    value_before = find_value(metrics_before, 'http_requests_total') or 0.0
    # do the request
    client.get('/my-view/')
    # collect the metric value again
    metrics_after = prometheus_client.REGISTRY.collect()
    value_after = find_value(metrics_after, 'http_requests_total')
    # the value should have increased by one
    assert value_after == value_before + 1.0

現在讓我們看看注冊表本身可以做什么。 請注意,這使用了prometheus-client內部結構,並且根據定義是脆弱的 - 使用風險自負!

prometheus-client內部混淆:取消注冊所有指標

如果您確定您的測試代碼將從頭開始調用指標注冊,您可以在測試開始之前從注冊表中取消注冊所有指標:

@pytest.fixture(autouse=True)
def clear_registry():
    collectors = tuple(prometheus_client.REGISTRY._collector_to_names.keys())
    for collector in collectors:
        prometheus_client.REGISTRY.unregister(collector)
    yield

請注意,這僅在您的測試代碼再次調用指標注冊時才有效,否則。 您將有效地停止指標收集,例如,內置的PlatformCollector將消失,直到您再次明確注冊它,例如通過prometheus_client.PlatformCollector()創建一個新實例。

prometheus-client內部結構混淆:重置(幾乎)所有指標

您還可以重置已注冊指標的值:

@pytest.fixture(autouse=True)
def reset_registry():
    collectors = tuple(prometheus_client.REGISTRY._collector_to_names.keys())
    for collector in collectors:
        try:
            collector._metrics.clear()
            collector._metric_init()
        except AttributeError:
            pass  # built-in collectors don't inherit from MetricsWrapperBase
    yield

這將重新實例化所有計數器/儀表/直方圖等的值和指標。上面的測試現在可以寫成

def test_counter_increases_by_one(client):
    # do the request
    client.get('/my-view/')
    # collect the metric value
    metrics_after = prometheus_client.REGISTRY.collect()
    value_after = find_value(metrics_after, 'http_requests_total')
    # the value should be one
    assert value_after == 1.0

當然,這不會重置內置收集器的任何指標,例如PlatformCollector因為它在實例化時只抓取一次值,或者ProcessCollector因為它根本不存儲任何值,而是從操作系統重新讀取它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM