簡體   English   中英

在 Sanic 中對偵聽器進行單元測試,而無需啟動應用服務器

[英]Unit test a listener in Sanic without starting the app server

假設我在我的 Sanic 應用程序中定義了這個監聽器:

@app.before_server_start
async def db_setup(*args):
    # ... set up the DB as I wish for the app

如果我想對這個 function (使用 pytest)進行單元測試,並將其導入到帶有from my.app import db_setup的單元測試文件中,似乎測試實際上開始為應用程序提供服務,因為 pytest 輸出:

[INFO] Goin' Fast @ http://0.0.0.0:8000
[INFO] Starting worker [485]

現在,我知道我可以通過執行db_setup = db_setup.__wrapped__來移除裝飾器的效果,但為了做到這一點,我實際上需要導入db_setup ,這是 Sanic 服務器啟動的地方。

有沒有辦法在導入時消除裝飾器的影響?

LE:我嘗試如下修補 Sanic 應用程序:

async def test_stuff(mocker):
    mocker.patch('myapp.app.app')  # last '.app' being `app = Sanic('MyApp')`
    imp = importlib.import_module('myapp.app')
    db_setup = getattr(imp, 'db_setup')
    await db_setup()

但現在我得到一個RuntimeError: Cannot run the event loop while another loop is runningmocker.patch('myapp.app.app')行運行。

我將在這里做一些假設,所以如果有一些澄清,我可能需要修改這個答案。

在開始之前,需要注意的是裝飾器本身不會啟動你的 web 服務器。 這將在以下兩種情況之一中運行:

  1. 您正在全局 scope 某處運行app.run()
  2. 您正在使用 Sanic TestClient ,它專門通過運行應用程序的 web 服務器來運行

現在,據我所知,您正在嘗試通過將其稱為 function 手動在測試中運行db_setup ,但您希望它在測試中作為偵聽器附加到應用程序。

您可以在app.listeners屬性中訪問所有應用程序實例的偵聽器。 因此,一種解決方案是這樣的:

# conftest.py
import pytest
from some.place import app as myapp

@pytest.fixture
def app():
    myapp.listeners = {}
    return myapp

就像我之前說的,這只會清空你的聽眾。 它實際上不會影響您的應用程序啟動,因此我不確定它是否具有您正在尋找的實用程序。


你應該能夠擁有這樣的東西:

from unittest.mock import Mock

import pytest
from sanic import Request, Sanic, json

app = Sanic(__name__)


@app.get("/")
async def handler(request: Request):
    return json({"foo": "bar"})


@app.before_server_start
async def db_setup(app, _):
    app.ctx.db = 999


@pytest.mark.asyncio
async def test_sample():
    await db_setup(app, Mock())

    assert app.ctx.db == 999

為了方便起見,它們都在同一個 scope 中,但即使測試函數、應用程序實例和偵聽器分布在不同的模塊中,最終結果也是一樣的:您可以像運行任何其他db_setup一樣運行 db_setup 和是否注冊為偵聽器都沒有關系。

暫無
暫無

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

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