如何执行异步函数的单元测试?

2024-06-28 11:33:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用Bleak来发现并连接到最近的蓝牙低能耗(BLE)设备,并且我正在编写单元测试(使用pytest)。在

我是Python测试的新手,我不知道如何处理这些补丁/mock,使其在async函数上工作。在

我不知道我是应该使用实际的函数,还是对默认函数应用补丁,使测试在没有BLE加密狗的情况下可执行。在

下面是一个代码示例(对discover.py的改进):

def list(op_sys: str) -> list:
    """list BLE devices

    Returns:
        list: status & list or error message
    """
    import asyncio, platform
    from bleak import discover

    async def run() -> list:
        """discover BLE devices

        Returns:
            list: status & list or error message
        """
        BLElist = []
        try:
            devices = await discover()
            for d in devices:
                print("'%s'" % d.name) # list devices
                BLElist.append(d.name)
            return 'success', BLElist
        except:
            return 'error', 'You don\'t have any BLE dongle.'

    # linux = 3.6, windows = 3.7, need a new loop to work
    if op_sys == "Windows":
        asyncio.set_event_loop(asyncio.new_event_loop())

    loop = asyncio.get_event_loop()
    return loop.run_until_complete(run())

我想知道是否应该重写该函数,将run()部分移到外部,并对其进行模拟。在


Tags: 函数runloopeventasyncioasyncreturndef
2条回答

因此,对于Freek的help,我知道我想嘲笑bleak.discover,下面是我如何做到的:

我找到了一个使用Ivan的this anwser的解决方案。在

这是我的测试:

import os, asyncio
from unittest.mock import Mock
from app.functions.ble import ble

class BLE:
    def __init__(self, name):
        self.name = name

# code of Ivan, thank you Ivan!
def async_return(result):
    f = asyncio.Future()
    f.set_result(result)
    return f

def test_list(monkeypatch):

    mock_discover = Mock(return_value=async_return([BLE("T-000001"), BLE("T-000002"), BLE("T-000003")]))
    monkeypatch.setattr('bleak.discover', mock_discover)
    list_BLE = ble.list("Linux")

    mock_discover.assert_called_once()
    assert list_BLE[0] == 'success'
    assert list_BLE[1][0] == "T-000001"

测试结果如下:

^{pr2}$

编辑:优雅代码建议:

from unittest import TestCase
from unittest.mock import patch
import os, asyncio

from app.functions.ble import ble


class DeviceDiscoveryTest(TestCase):

    @staticmethod
    def __async_return(result):
        f = asyncio.Future()
        f.set_result(result)
        return f

   @classmethod
   def mocked_discover(cls):
        return cls.__async_return([BLE("T-000001"), BLE("T-000002"), BLE("T-000003")])

    @patch('bleak.discocver', new=DeviceDiscoveryTest.mocked_discover)
    def test_discover_devices(self):
        list_BLE = ble.list("Linux")
        self.assertEquals('success', list_BLE[0])
        ....

外部函数list(op_sys) -> list不是异步的,因为它调用了loop.run_until_complete。在

这样就可以像任何同步python函数一样进行单元测试。在

如果您想对内部函数run() -> list等异步函数进行单元测试,请看这里:https://pypi.org/project/asynctest/。在

相关问题 更多 >