Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock asyncio coroutines?

Tags:

The following code fails with TypeError: 'Mock' object is not iterable in ImBeingTested.i_call_other_coroutines because I've replaced ImGoingToBeMocked by a Mock object.

How can I mock coroutines?

class ImGoingToBeMocked:     @asyncio.coroutine     def yeah_im_not_going_to_run(self):         yield from asyncio.sleep(1)         return "sup"  class ImBeingTested:     def __init__(self, hidude):         self.hidude = hidude      @asyncio.coroutine     def i_call_other_coroutines(self):         return (yield from self.hidude.yeah_im_not_going_to_run())  class TestImBeingTested(unittest.TestCase):      def test_i_call_other_coroutines(self):         mocked = Mock(ImGoingToBeMocked)         ibt = ImBeingTested(mocked)          ret = asyncio.get_event_loop().run_until_complete(ibt.i_call_other_coroutines()) 
like image 547
Dustin Wyatt Avatar asked Apr 26 '15 17:04

Dustin Wyatt


People also ask

How do you mock a coroutine in Python?

data = iter([b'data', b'']) @asyncio. coroutine def read(*args): return next(data) mocked. read = Mock(wraps=read) # Here, the business class would use its . read() method which # would first read 4 bytes of data, and then no data # on its second read.

What is Asyncio Create_task?

The method create_task takes a coroutine object as a parameter and returns a Task object, which inherits from asyncio. Future . The call creates the task inside the event loop for the current thread, and starts the task executing at the beginning of the coroutine's code-block.

What is Ensure_future Asyncio?

October 10, 2019 October 10, 2019 Sebastian asyncio. tl;dr ensure_future let's us execute a coroutine in the background, without explicitly waiting for it to finish. If we need, we can wait for it later or poll for result. In other words, this is a way of executing code in asyncio without await.


2 Answers

Since mock library doesn't support coroutines I create mocked coroutines manually and assign those to mock object. A bit more verbose but it works.

Your example may look like this:

import asyncio import unittest from unittest.mock import Mock   class ImGoingToBeMocked:     @asyncio.coroutine     def yeah_im_not_going_to_run(self):         yield from asyncio.sleep(1)         return "sup"   class ImBeingTested:     def __init__(self, hidude):         self.hidude = hidude      @asyncio.coroutine     def i_call_other_coroutines(self):         return (yield from self.hidude.yeah_im_not_going_to_run())   class TestImBeingTested(unittest.TestCase):      def test_i_call_other_coroutines(self):         mocked = Mock(ImGoingToBeMocked)         ibt = ImBeingTested(mocked)          @asyncio.coroutine         def mock_coro():             return "sup"         mocked.yeah_im_not_going_to_run = mock_coro          ret = asyncio.get_event_loop().run_until_complete(             ibt.i_call_other_coroutines())         self.assertEqual("sup", ret)   if __name__ == '__main__':     unittest.main() 
like image 55
Andrew Svetlov Avatar answered Oct 04 '22 22:10

Andrew Svetlov


I am writting a wrapper to unittest which aims at cutting the boilerplate when writting tests for asyncio.

The code lives here: https://github.com/Martiusweb/asynctest

You can mock a coroutine with asynctest.CoroutineMock:

>>> mock = CoroutineMock(return_value='a result') >>> asyncio.iscoroutinefunction(mock) True >>> asyncio.iscoroutine(mock()) True >>> asyncio.run_until_complete(mock()) 'a result' 

It also works with the side_effect attribute, and an asynctest.Mock with a spec can return CoroutineMock:

>>> asyncio.iscoroutinefunction(Foo().coroutine) True >>> asyncio.iscoroutinefunction(Foo().function) False >>> asynctest.Mock(spec=Foo()).coroutine <class 'asynctest.mock.CoroutineMock'> >>> asynctest.Mock(spec=Foo()).function <class 'asynctest.mock.Mock'> 

All the features of unittest.Mock are expected to work correctly (patch(), etc).

like image 37
Martin Richard Avatar answered Oct 04 '22 20:10

Martin Richard