Python 3.10 中是否有与unitsetUpClass 等效的异步方法?

问题描述 投票:0回答:2

我一直在使用

unittest.IsolatedAsyncioTestCase
来测试我的异步方法。我一直在使用
setUpClass
asyncSetUp
创建固定装置,并使用
asyncTearDown
进行清理。到目前为止一切进展顺利:-)

但是现在我有一个新的要求,即为每个测试类异步创建一些固定装置,并在整个测试方法中使用它。

我知道

setUpClass
每个测试类运行一次,而
setUp
每个测试方法运行一次。
asyncSetUp
setUp
的异步等价物。但我似乎找不到
setUpClass
的异步等价物。

那么,每次测试异步创建和清理夹具的最佳方法是什么?

我尝试在 https://docs.python.org/3/library/unittest.html#unittest.TestCase.setUpClass 检查官方单元测试文档,但它仅记录有关

asyncSetUp
的文档。

我使用的是 Python 3.10 并使用 pytest。

python python-3.x pytest python-unittest pytest-asyncio
2个回答
1
投票

没有现成的解决方案

asyncSetUpClass
,但您可以使用几种解决方案:

解决方案 1 - 一次性初始化上下文

from unittest import IsolatedAsyncioTestCase

class TestsContext():

    def __init__(self) -> None:
        self.init_done: bool = False

    async def set_up(self):
        if self.init_done:
            return

        # DO INITIALIZATION HERE

        self.init_done = True

class MyServiceTests(IsolatedAsyncioTestCase):

    context: TestsContext = TestsContext()

    async def asyncSetUp(self):
        await self.context.set_up()

    async def test_send_request(self):
        # test implementation

解决方案 2 - 在新事件循环中运行

import asyncio
import threading
from typing import Awaitable
from unittest import IsolatedAsyncioTestCase

def run_in_new_event_loop(worker: Awaitable, *args, **kwargs):
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        thread = threading.current_thread()
        print(f'Thread {thread.ident}/{thread.name} for {worker}')
        return loop.run_until_complete(worker(*args, **kwargs))
    finally:
        if not loop.is_closed():
            loop.close()

class TestsContext():

    async def set_up(self):
        # DO SETUP HERE

    async def tear_down(self):
        # DO TEAR DOWN HERE        

class MyServiceTests(IsolatedAsyncioTestCase):

    context: TestsContext = TestsContext()

    @staticmethod
    def setUpClass():
        run_in_new_event_loop(MyServiceTests.context.set_up)

    @staticmethod
    def tearDownClass():
        run_in_new_event_loop(MyServiceTests.context.tear_down)

1
投票

我发现有效的方法如下:在标准

setUpClass
调用中,您可以添加一个新的事件循环作为类属性,然后运行它:

@classmethod
def setUpClass(cls) -> None:

    # Handling asynchronous set up
    cls.loop = asyncio.new_event_loop()  # create and set new event loop
    asyncio.set_event_loop(cls.loop)
    cls.loop.run_until_complete(cls.asyncSetUpClass())

@classmethod
async def asyncSetUpClass(cls):
    # assign measurement object to unit test object
    cls.async_attribute = await AsyncFunc()


@classmethod
def tearDownClass(cls) -> None:
    if cls.loop.is_running():
        cls.loop.stop()
    cls.loop.close()

这使我能够使用异步函数提供的属性设置多次测试所需的属性,只需一次。我不完全确定拆解的实用性,但这似乎是一个很好的措施。

我还发现我可以这样做:

@classmethod
def setUpClass(cls) -> None:
  async.run(cls.asyncSetUpClass())

@classmethod
async def asyncSetUpClass(cls):
    # assign measurement object to unit test object
    cls.async_attribute = await AsyncFunc()
© www.soinside.com 2019 - 2024. All rights reserved.