为mocked asyncio.coroutine

时间:2015-11-12 22:38:19

标签: python unit-testing python-unittest python-asyncio

我正在尝试在我正在测试的类中模拟一个辅助方法,但是我无法设置返回值。它取而代之的是None,这会导致调用方法出错。

import unittest
import asyncio
import unittest.mock

class MyClass:

    @asyncio.coroutine
    def return_number(self):
        return 5

    @asyncio.coroutine
    def add_two(self):
        val = yield from self.return_number()
        return val + 2


class TestMyClass(unittest.TestCase):

    def setUp(self):
        self.mc = MyClass()

    def test_add(self):
        val = asyncio.get_event_loop().run_until_complete(self.mc.add_two())
        self.assertEqual(val, 7)

    def test_with_mock(self):
        """ Replace return_number with mocked method """
        mm = unittest.mock.MagicMock()
        mm.iter.return_value = 2
        self.mc.return_number = unittest.mock.Mock(return_value=mm)

        val = asyncio.get_event_loop().run_until_complete(self.mc.add_two())
        self.assertEqual(val, 4)


if __name__ == '__main__':
    unittest.main()

在这个例子中有没有办法模拟return_number,以便它返回一个特定的值?

3 个答案:

答案 0 :(得分:3)

你也可以做类似的事情:

def test_with_mock(self):
    """ Replace return_number with mocked method """
    with mock.patch.object(self.mc, "return_number", return_value=2):
        self.mc.return_number = asyncio.coroutine(self.mc.return_number)
        val = asyncio.get_event_loop().run_until_complete(self.mc.add_two())
        self.assertEqual(val, 4)

答案 1 :(得分:0)

我找到了一个解决方案,虽然我更喜欢类似上面的test_with_mock,我可以手动设置返回值,而不是提供函数。

def test_with_patch(self):
    """ This one seems to work """
    @asyncio.coroutine
    def fake_ret_num(self):
        return 2

    with unittest.mock.patch.object(mc.MyClass, 'return_number', 
                                    fake_ret_num) as mock_meth:

        val = asyncio.get_event_loop().run_until_complete(self.mc.add_two())
        self.assertEqual(val, 4)

答案 2 :(得分:0)

您也可以使用aiounittest并使用其futurized

要测试的代码:

# dummy_math.py

from asyncio import sleep

async def add(x, y):
    await sleep(666)
    return x + y

使用AsyncTestCase进行测试并将其作为模拟return_value进行预测:

from aiounittest import futurized, AsyncTestCase
from unittest.mock import Mock, patch

import dummy_math

class MyTest(AsyncTestCase):

    def tearDown(self):
        super().tearDown()
        patch.stopall()

    async def test_add(self):
        mock_sleep = Mock(return_value=futurized('whatever'))
        patch('dummy_math.sleep', mock_sleep).start()
        ret = await dummy_math.add(5, 6)
        self.assertEqual(ret, 11)
        mock_sleep.assert_called_once_with(666)

    async def test_fail(self):
        mock_sleep = Mock(return_value=futurized(Exception('whatever')))
        patch('dummy_math.sleep', mock_sleep).start()
        with self.assertRaises(Exception) as e:
            await dummy_math.add(5, 6)
        mock_sleep.assert_called_once_with(666)