结合py.test和trio / curio

时间:2018-01-18 20:42:59

标签: python pytest python-trio curio

我想结合pytest和trio(或curio,如果这更容易),即将我的测试用例写成协程函数。通过在conftest.py

中声明自定义测试运行器,这相对容易实现
    @pytest.mark.tryfirst
    def pytest_pyfunc_call(pyfuncitem):
        '''If item is a coroutine function, run it under trio'''

        if not inspect.iscoroutinefunction(pyfuncitem.obj):
            return

        kernel = trio.Kernel()
        funcargs = pyfuncitem.funcargs
        testargs = {arg: funcargs[arg]
                    for arg in pyfuncitem._fixtureinfo.argnames}
        try:
            kernel.run(functools.partial(pyfuncitem.obj, **testargs))
        finally:
            kernel.run(shutdown=True)

        return True

这允许我编写这样的测试用例:

    async def test_something():
        server = MockServer()
        server_task = await trio.run(server.serve)
        try:
             # test the server
        finally:
             server.please_terminate()
             try:
                 with trio.fail_after(30):
                     server_task.join()
             except TooSlowError:
                 server_task.cancel()

但这是很多样板。在非异步代码中,我会将其分解为一个夹具:

@pytest.yield_fixture()
def mock_server():
    server = MockServer()
    thread = threading.Thread(server.serve)
    thread.start()

    try:
        yield server
    finally:
        server.please_terminate()
        thread.join()
        server.server_close()

def test_something(mock_server):
   # do the test..

有没有办法在三重奏中做同样的事情,即实现异步装置?理想情况下,我只想写:

async def test_something(mock_server):
   # do the test..

1 个答案:

答案 0 :(得分:2)

编辑:下面的答案现在大多不相关 - 而是使用pytest-trio并按照instructions in its manual

您的示例popupContentView.popupInteractionGestureRecognizer代码并不起作用,因为它是三重奏和古玩的混合物:-)。对于trio,有一个装饰器pytest_pyfunc_call,可用于标记单个测试(如果你使用经典的单元测试或其他东西),所以编写pytest插件函数的最简单方法是将其应用于每个异步测试:

trio.testing.trio_test

如果你有点好奇,这基本上相当于:

from trio.testing import trio_test

@pytest.mark.tryfirst
def pytest_pyfunc_call(pyfuncitem):
    if inspect.iscoroutine(pyfuncitem.obj):
        # Apply the @trio_test decorator
        pyfuncitem.obj = trio_test(pyfuncitem.obj)

无论如何,这并没有解决你的问题 - 因为你需要更多的东西。