Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RuntimeWarning: coroutine was never awaited in tests

Tags:

python

pytest

I'm trying to test a async Python function using pytest. My test is passing with a warning, when it should be failing.

This is my test:

import asynctest
import pytest

from Foo.bar import posts

@pytest.mark.asyncio
async def test_get_post_exists():
    returned_post = await posts.get_post('0')

    assert returned_post.id == 0
    assert returned_post.text == 'Text for the post body.'
    assert True == False

It passes with the following message:

================================== test session starts ===================================
platform darwin -- Python 3.6.4, pytest-3.4.2, py-1.5.2, pluggy-0.6.0
rootdir: /path/path/path/path, inifile:
collected 1 item

tests/unit/route_logic/test_post_helpers.py .                                      [100%]

==================================== warnings summary ====================================
tests/unit/route_logic/test_post_helpers.py::test_get_post_exists
  /usr/local/lib/python3.6/site-packages/_pytest/python.py:155: RuntimeWarning: coroutine 'test_get_post_exists' was never awaited
    testfunction(**testargs)

-- Docs: http://doc.pytest.org/en/latest/warnings.html
========================== 1 passed, 1 warnings in 0.10 seconds ==========================
like image 363
Jones Avatar asked Mar 18 '18 17:03

Jones


People also ask

Is Coroutine deprecated?

"@coroutine" decorator is deprecated since Python 3.8, use "async def" instead.

How do I use async await in Python?

The async/await keywords They simplify asynchronous programming in Python. The async keyword is used to create a Python coroutine. The await keyword suspends execution of a coroutine until it completes and returns the result data. The await keywords only works within an async function.


2 Answers

Here is the working demo using pytest and pytest-asyncio:

Foo/bar/posts.py:

from collections import namedtuple

Post = namedtuple('Post', 'id text')


async def get_post(id: str):
    return Post(id=int(id), text='Text for the post body.')

test_post_helpers.py:

import pytest

from Foo.bar import posts


@pytest.mark.asyncio
async def test_get_post_exists():
    returned_post = await posts.get_post('0')
    assert returned_post.id == 0
    assert returned_post.text == 'Text for the post body.'
    assert True == False

Unit test result:

========================================================================================================================================================================= test session starts ==========================================================================================================================================================================
platform darwin -- Python 3.7.5, pytest-5.3.1, py-1.8.0, pluggy-0.13.1
rootdir: /Users/ldu020/workspace/github.com/mrdulin/python-codelab
plugins: asyncio-0.10.0
collected 1 item                                                                                                                                                                                                                                                                                                                                                       

src/stackoverflow/49350821/test_post_helpers.py F                                                                                                                                                                                                                                                                                                                [100%]

=============================================================================================================================================================================== FAILURES ===============================================================================================================================================================================
_________________________________________________________________________________________________________________________________________________________________________ test_get_post_exists _________________________________________________________________________________________________________________________________________________________________________

    @pytest.mark.asyncio
    async def test_get_post_exists():
        returned_post = await posts.get_post('0')
        assert returned_post.id == 0
        assert returned_post.text == 'Text for the post body.'
>       assert True == False
E       assert True == False

src/stackoverflow/49350821/test_post_helpers.py:11: AssertionError
========================================================================================================================================================================== 1 failed in 0.15s ===========================================================================================================================================================================

assert True == False cause the assertion fails as you wish.

Source code: https://github.com/mrdulin/python-codelab/tree/master/src/stackoverflow/49350821

like image 136
slideshowp2 Avatar answered Sep 20 '22 13:09

slideshowp2


You have to install pytest-asyncio.

pip install pytest-asyncio

You don't have to import it anywhere. Just decorate the async def tests with @pytest.mark.asyncio.

It was mentioned by in the @hoefling comments, I'm posting this answer just to make it more visible:

coroutine 'my_coro' was never awaited means that the coroutine object was never put into the event loop, so I suppose you are either missing pytest-asyncio that puts tests into event loop.

Without pytest-asyncio, pytest doesn't know that it should await the async test. It just runs it as a non-async function, which is not enough to actually execute the async function body:

$ python3
Python 3.7.3 (default, Apr  3 2019, 05:39:12)
>>> async def foo():
...   raise Excepion('this is never raised')
...
>>> foo()
<coroutine object foo at 0x7f7d857d4cc8>
>>> exit()
sys:1: RuntimeWarning: coroutine 'foo' was never awaited
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
like image 22
Messa Avatar answered Sep 17 '22 13:09

Messa