Skip to content

Dealing with async functions #155

@keis

Description

@keis

When there is a async function we want to test

async def frobnicate(arg0):
    raise ValueError("Could not do it")

naïvely we may write (spoiler alert this will not work)

assert_that(calling(frobnicate).with_args(5), raises(ValueError))

As a first suggestion it would be nice if the error message could guide me in the right direction like

Expected: Expected a callable raising <class 'ValueError'>
     but: Coroutine returned (Did you mean to await the call)

There's a couple of ways of testing this function that does work but they look a bit clunky or have other issues. Does anyone have suggestions on how to better to do this?

a) using run_until_complete

def calling_async(callable: Callable, *, loop: Loop):
    def wrapper(*args, **kwargs):
        loop.run_until_complete(callable(*args, **kwargs))
    return calling(wrapper)

assert_that(calling_async(frobnicate, loop=loop).with_args(5), raises(ValueError)

Looks pretty neat but has the big down side it's not possible to use when the test method itself is async (like when using pytest-async)

b) testing the result function of a future instead

async def resolved(obj):
    fut = asyncio.ensure_future(obj)
    await asyncio.wait([fut])
    return fut

async def test_frobnicate():
    future = await resolved(frobnicate(5))
    assert_that(calling(future.result), rasise(ValueError))

This is arguably the more sane approach but with the assert line only being calling(future.result) it loses some context.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions