摘要:整個(gè)事件循環(huán)是在一個(gè)線程里面的,意味著任務(wù)切換更加高效,無(wú)需上下文轉(zhuǎn)換。異步代碼很高效,但是也有很蛋疼的地方,那就是測(cè)試。所以我們得想辦法告訴使用一個(gè)來(lái)運(yùn)行測(cè)試方法。
視頻原文:Strategies for testing Async code - PyCon 2019
同時(shí)參考了:
Testing Asyncio Python Code with Pytest
前面幾篇關(guān)于異步編程的文章:
異步編程 101: 是什么、小試Python asyncio
異步編程 101:Python async await發(fā)展簡(jiǎn)史
異步編程 101:寫(xiě)一個(gè)事件循環(huán)
異步編程 101:asyncio中的 for 循環(huán)
異步編程 101:asyncio 進(jìn)階上篇
異步編程,本質(zhì)上是通過(guò)合作(cooperation)來(lái)達(dá)成并發(fā)效果,也即:需要 wait 的時(shí)候,也就是發(fā)生 IO 的時(shí)候,把控制權(quán)交給主事件循環(huán)。 (yield control when "awaiting" asynchronous results.) 這個(gè)過(guò)程有點(diǎn)像事件循環(huán)完成了操作系統(tǒng)的工作,可以將事件循環(huán)看作是操作系統(tǒng),然后把協(xié)程看作是線程這么來(lái)理解。整個(gè)事件循環(huán)是在一個(gè)線程里面的,意味著任務(wù)切換更加高效,無(wú)需上下文轉(zhuǎn)換。
異步代碼很高效,但是也有很蛋疼的地方,那就是測(cè)試。
0x01 : async 測(cè)試實(shí)例來(lái)通過(guò)一個(gè)簡(jiǎn)單的例子看一下吧:一個(gè)Cat類,有一個(gè) move 方法,這個(gè)方法是異步的。
然后用 unittest 寫(xiě)一個(gè)測(cè)試類,你能發(fā)現(xiàn)下面代碼的問(wèn)題嗎?
herd(grafield, "forward") 返回的是一個(gè)協(xié)程對(duì)象(coroutine object),如果你不await他,什么也不會(huì)發(fā)生。而coroutine object是 truthy 的,所以assertTrue() 是能夠通過(guò)的。如果你運(yùn)行一下 test,會(huì)看到coroutine herd was nerver awaited的 warning。
下圖這樣調(diào)用await還是不對(duì)的,因?yàn)?b>await關(guān)鍵字只能出現(xiàn)在async函數(shù)里面。
一個(gè)解決方案是加入事件循環(huán):
這能work,但是估計(jì)你也看出來(lái)了,這很麻煩。如果我有多個(gè)方法,難道我需要每個(gè) test方法都加一個(gè)事件循環(huán)嗎?更重要的是,我只是想做一下單元測(cè)試,事件循環(huán)在這個(gè)時(shí)候?qū)嶋H上是一個(gè)底層細(xì)節(jié),我不需要關(guān)心。
在 Python3.7 中,asyncio新增了一個(gè)方法:asyncio.run(),為你隱藏了事件循環(huán)的細(xì)節(jié),所以能夠讓代碼更加簡(jiǎn)潔:
0x02 pytest-asyncio
安裝:pip install pytest-asyncio,這實(shí)際上是pytest的一個(gè)插件。
用法很簡(jiǎn)單,重要的是我們得知道工作原理。之前的代碼問(wèn)題在于,pytest 默認(rèn)的的 runner 會(huì)將所有的函數(shù)當(dāng)作普通函數(shù)處理,而對(duì)于 async 函數(shù), 調(diào)用的時(shí)候返回的是一個(gè) coroutine object。所以我們得想辦法告訴 pytest 使用一個(gè) eventloop 來(lái)運(yùn)行測(cè)試方法。
一種方法是,實(shí)例化一個(gè)eventloop 然后注入到 tests里面,比如:
import asyncio
import pytest
async def say(what, when):
await asyncio.sleep(when)
return what
@pytest.fixture
def event_loop():
loop = asyncio.get_event_loop()
yield loop
loop.close()
def test_say(event_loop):
expected = "This should fail!"
assert expected == event_loop.run_until_complete(say("Hello!", 0))
這種方法不方便之處在于每次都需要手動(dòng)注入 eventloop,更優(yōu)雅的方法是調(diào)整 test runner,讓它識(shí)別 async 函數(shù),當(dāng)作 asyncio tasks 來(lái)執(zhí)行。
pytest-asyncio完成的功能就是這樣的,它的 API 非常簡(jiǎn)單,你只需要為 async function 添加一個(gè) @pytest.mark.asyncio 修飾器即可:
import pytest
from say import say
@pytest.mark.asyncio
async def test_say():
assert "Hello!" == await say("Hello!", 0)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/7001.html
摘要:蜂鳥(niǎo)網(wǎng)圖片簡(jiǎn)介今天玩點(diǎn)新鮮的,使用一個(gè)新庫(kù),利用它提高咱爬蟲(chóng)的爬取速度。上下文不在提示,自行搜索相關(guān)資料即可創(chuàng)建一個(gè)對(duì)象,然后用該對(duì)象去打開(kāi)網(wǎng)頁(yè)。可以進(jìn)行多項(xiàng)操作,比如等代碼中等待網(wǎng)頁(yè)數(shù)據(jù)返回創(chuàng)建線程,方法負(fù)責(zé)安排執(zhí)行中的任務(wù)。 1. 蜂鳥(niǎo)網(wǎng)圖片-簡(jiǎn)介 今天玩點(diǎn)新鮮的,使用一個(gè)新庫(kù) aiohttp ,利用它提高咱爬蟲(chóng)的爬取速度。 安裝模塊常規(guī)套路 pip install aiohtt...
摘要:蜂鳥(niǎo)網(wǎng)圖片簡(jiǎn)介今天玩點(diǎn)新鮮的,使用一個(gè)新庫(kù),利用它提高咱爬蟲(chóng)的爬取速度。上下文不在提示,自行搜索相關(guān)資料即可創(chuàng)建一個(gè)對(duì)象,然后用該對(duì)象去打開(kāi)網(wǎng)頁(yè)??梢赃M(jìn)行多項(xiàng)操作,比如等代碼中等待網(wǎng)頁(yè)數(shù)據(jù)返回創(chuàng)建線程,方法負(fù)責(zé)安排執(zhí)行中的任務(wù)。 1. 蜂鳥(niǎo)網(wǎng)圖片-簡(jiǎn)介 今天玩點(diǎn)新鮮的,使用一個(gè)新庫(kù) aiohttp ,利用它提高咱爬蟲(chóng)的爬取速度。 安裝模塊常規(guī)套路 pip install aiohtt...
摘要:蜂鳥(niǎo)網(wǎng)圖片簡(jiǎn)介今天玩點(diǎn)新鮮的,使用一個(gè)新庫(kù),利用它提高咱爬蟲(chóng)的爬取速度。上下文不在提示,自行搜索相關(guān)資料即可創(chuàng)建一個(gè)對(duì)象,然后用該對(duì)象去打開(kāi)網(wǎng)頁(yè)??梢赃M(jìn)行多項(xiàng)操作,比如等代碼中等待網(wǎng)頁(yè)數(shù)據(jù)返回創(chuàng)建線程,方法負(fù)責(zé)安排執(zhí)行中的任務(wù)。 1. 蜂鳥(niǎo)網(wǎng)圖片-簡(jiǎn)介 今天玩點(diǎn)新鮮的,使用一個(gè)新庫(kù) aiohttp ,利用它提高咱爬蟲(chóng)的爬取速度。 安裝模塊常規(guī)套路 pip install aiohtt...
摘要:發(fā)現(xiàn)一個(gè)月沒(méi)刷技術(shù)文章了有點(diǎn)慌整理一篇短的用法出來(lái)只包含最基本的用法在里邊最清晰不過(guò)我是在寫(xiě)的版本的實(shí)現(xiàn)包含異步用法會(huì)更繁瑣一些但是也值得看看我相信普及之前還是一個(gè)很有意思的選擇我的代碼寫(xiě)的是可以自動(dòng)腦補(bǔ)圓括號(hào)花括號(hào)上去注意包含的函數(shù)自動(dòng) 發(fā)現(xiàn)一個(gè)月沒(méi)刷技術(shù)文章了, 有點(diǎn)慌, 整理一篇短的 CSP 用法出來(lái),只包含最基本的用法, 在 Go 里邊最清晰, 不過(guò)我是在 Clojure 寫(xiě)的...
閱讀 2731·2021-11-23 09:51
閱讀 2445·2021-09-30 09:48
閱讀 2082·2021-09-22 15:24
閱讀 1047·2021-09-06 15:02
閱讀 3360·2021-08-17 10:14
閱讀 1971·2021-07-30 18:50
閱讀 2007·2019-08-30 15:53
閱讀 3215·2019-08-29 18:43