pythonmock方法
A. python unittest沒有mockobject嗎
有的 Fudge, pmock, python-mock之類的
B. 說說這篇我為什麼從python轉向go
恩看了這篇我為什麼從python轉向go,
看來作者也是 KSO 輕辦公/企業快盤團隊的。作為快盤從無到有時期的工程師之一(總是被瀟灑哥說他們改我留下的 bug ),又恰好是
Python/Go 雙修(大霧其實我是 Rust 黨),其實一開始我是拒絕的,ang ang ang,那就隨手寫一點把。
一段段來吧,首先作者說 Python 是動態語言
python是一門動態語言,不是強類型系統。對於一個變數,我們有時候壓根不知道它是什麼類型,然後就可能出現int + string這樣的運行時錯誤。
在python裡面,可以允許同名函數的出現,後一個函數會覆蓋前一個函數,有一次我們系統一個很嚴重的錯誤就是因為這個導致的。
事實上,如果是靜態檢查,pylint 和 pyflakes 是可以做這件事的,雖然不能和 go
那種靜態編譯型語言比,但也足夠了。如果沒記錯的話,阿通當年是要求全組都在提交前做靜態檢查的。我認為這種問題更多的應該是人員素質上來避免,畢竟蔥頭
也說過,代碼自己寫的就要多回頭看看,看能不能重構,能不能做更好。不是說偷懶不行,但是從中得出 Python
動態特性太靈活,Python:怪我咯看
另外,函數作為第一對象,在 Python 中是 feature,Go 要寫個 mock,簡直虐得不要不要的。
其實這個一直是很多人吐槽python的地方,不過想想,python最開始是為了解決啥問題而被開發出來的看我們硬是要將他用到高性能伺服器開發上面,其實也是有點難為它。
如果沒記錯,無論是輕辦公還是快盤,是重 IO 不重 CPU,最大耗時是數據塊加密那塊,我在的時候是 java 寫的。另外高性能伺服器選 Go 也是虐得不要不要的,各種小心翼翼避免 GC。大多數極端情況下,pypy 的性能足矣勝任了,我認為這不算充分條件。
python的GIL導致導致無法真正的多線程,大家可能會說我用多進程不就完了。但如果一些計算需要涉及到多進程交互,進程之間的通訊開銷也是不得不考慮的。
其實,Python 有宏可以繞開這個 GIL,但是呢架構設計得好其實可以避免的,到非同步那塊我會說。
無狀態的分布式處理使用多進程很方便,譬如處理http請求,我們就是在nginx後面掛載了200多個django server來處理http的,但這么多個進程自然導致整體機器負載偏高。
但即使我們使用了多個django進程來處理http請求,對於一些超大量請求,python仍然處理不過來。所以我們使用openresty,將高頻次的http請求使用lua來實現。可這樣又導致使用兩種開發語言,而且一些邏輯還得寫兩份不同的代碼。
如果推測沒錯,你們現在還在用五年前寫的 Gateway看那個基於 django route
的流量分發層看四年前我離開的時候已經小范圍的使用 Flask+Gevent Demo 測試過了,無論是性能還是負載都比同步模型的 django
有優勢。如果還是 django
這套的話,我只能說比較遺憾,畢竟當年金山新員工大賽頭牌就是我和幾個小夥伴寫的實時同步在線文檔編輯系統,用的就是這套技術。
因此這是個工程問題,並非語言問題。 Python 提供給了你了這么多工具,硬要選一個傳統的,Old fashion 的,Python:怪我咯看
django的網路是同步阻塞的,也就是說,如果我們需要訪問外部的一個服務,在等待結果返回這段時間,django不能處理任何其他的邏輯(當然,多線程的除外)。如果訪問外部服務需要很長時間,那就意味著我們的整個服務幾乎在很長一段時間完全不可用。
為了解決這個問題,我們只能不斷的多開django進程,同時需要保證所有服務都能快速的處理響應,但想想這其實是一件很不靠譜的事情。
同步模型並非不行,因為 overhead 足夠低,很多業務場景下用同步模型反而會取得更好的效果,比如豆瓣。同步模型最大的問題是對於 IO 密集型業務等待時間足夠長,這時候需要的不是換語言 ,而是提醒你是不是架構要改一下了。
雖然tornado是非同步的,但是python的mysql庫都不支持非同步,這也就意味著如果我們在tornado裡面訪問資料庫,我們仍然可能面臨因為資料庫問題造成的整個服務不可用。
tornado 是有這個問題,但是 gevent 已經解決了。我在 node.js 的某問題下曾經回答過,對於 node
而言,能選擇的非同步模型只有一個,而 Python 就是太多選擇了。另外 pypy+tornado+redis
可以隨意虐各種長連接的場景,比如我給我廠寫過的一個 push service。
其實非同步模型最大的問題在於代碼邏輯的割裂,因為是事件觸發的,所以我們都是通過callback進行相關處理,於是代碼裡面就經常出現干一件事情,傳一個callback,然後callback裡面又傳callback的情況,這樣的結果就是整個代碼邏輯非常混亂。
這個還真不是,如果說沒有 ES6 的 JavaScript,可能真有 Callback hell,但這是 Python 啊!Python
早就實現了左值綁定唉,yield 那姿勢比某些天天吹的語言不知道高到哪裡去了,當然我說的是完整版的 Python3 yield。即便是不完整的
Python 2 yield 用於非同步表達式求值也是完全足夠的,tornado 的 gen.coroutine 啊。
同步形態寫非同步,在 Python 實力強的公司裡面早普及了,這是個工程問題,並非語言問題。當然把這種事怪在 Python 身上,Python:怪我咯看
python沒有原生的協程支持,雖然可以通過gevent,greenlet這種的上patch方式來支持協程,但畢竟更改了python源碼。另外,python的yield也可以進行簡單的協程模擬,但畢竟不能跨堆棧,局限性很大,不知道3.x的版本有沒有改進。
無論是 Gevent 還是 Greenlet 均沒修改 Python 源碼,事實上這貨已經成為了 Py2 coroutine 的標准,加上豆瓣開源出來的greenify,基本上所有的庫都可以平滑的非同步化,包括 MySQL 等 C 一級的 lib。自從用上這套技術後,豆瓣的 Python dev 各種爽得不要不要的。
當我第一次使用python開發項目,我是沒成功安裝上項目需要的包的,光安裝成功mysql庫就弄了很久。後來,是一位同事將他整個python目錄打包給我用,我才能正常的將項目跑起來。話說,現在有了docker,是多麼讓人幸福的一件事情。
而部署python服務的時候,我們需要在伺服器上面安裝一堆的包,光是這一點就讓人很麻煩,雖然可以通過puppet,salt這些自動化工具解決部署問題,但相比而言,靜態編譯語言只用扔一個二進制文件,可就方便太多了。
恰好我又是在開發基於 docker 的平台, docker 還真不是用來做部署這事的。首先, Python 是有 virtualenv
這個工具的,事實上對比包管理和包隔離,Python 比 Go 高得不知道哪裡去了。Python 跟 Git 談笑風生的時候, Go 的 dev
們還得考慮我怎樣才能使得 import 的包穩定在一個版本上(當然現在有很多第三方方案)。Virtualenv + Pip 完全可以實現
Python 部署自動化,所以這個問題我認為是,工具鏈選取問題。畢竟是個十幾年的老妖怪了,Python
啥情況沒見過啊,各種打包工具任君選擇,強行說 Python 部署不方便,Python:怪我咯看
python非常靈活簡單,寫c幾十行代碼才能搞定的功能,python一行代碼沒准就能解決。但是太簡單,反而導致很多
同學無法對代碼進行深層次的思考,對整個架構進行細致的考量。來了一個需求,啪啪啪,鍵盤敲完開速實現,結果就是代碼越來越混亂,最終導致了整個項目代碼
失控。
曾經知乎有個帖子問 Python 會不會降低程序員編程能力,
我只能說這真的很人有關。你不去思考深層次的東西怪語言不行是沒道理的,那好,Go 裡面 goroutine 是怎麼實現的,一個帶 socket 的
goroutine
最小能做到多少內存,思考過看任何語言都有自己的優勢和劣勢,都需要執行者自己去判斷,一味的覺得簡單就不會深入思考這是有問題的。另外,代碼混亂我認為
還是工程上的控制力不夠,豆瓣有超過10W行的 Python 實現,雖然不說很完美,大體上做到了不會混亂這么個目標。
還有,C 寫幾十行搞定的 Python 一行解決這絕對是重大 feature,生產力啊,人員配置啊,招人培養的成本啊,從工程上來說,Python 在這一塊完全是加分項,不是每個項目都要求極致的並發,極致的效率,做工程很多時候都是要取捨的。
雖然java和php都是最好的編程語言(大家都這么爭的),但我更傾向一門更簡單的語言。而openresty,雖然性
能強悍,但lua仍然是動態語言,也會碰到前面說的動態語言一些問題。最後,前金山許式偉用的go,前快盤架構師蔥頭也用的go,所以我們很自然地選擇了
go。
Openresty 用 lua 如果按照動態語言的角度去看,還真算不上,頂多是個簡單點的 C。許式偉走的時候大多數都是
CPP,蔥頭目前我還不知道他創業用的是什麼寫的,不過他肯定沒語言傾向。當年無論是 leo 還是 ufa,一個用 Python 一個用
Java, 他都是從工程實際來選擇使用什麼樣的語言。
error,好吧,如果有語言潔癖的同學可能真的受不了go的語法,尤其是約定的最後一個返回值是error。
這其實是 Go style,無論是 go fmt 還是 error style,Go 其實是想抹平不同工程師之間的風格問題。不再為了一個縮進和大括弧位置什麼的浪費時間。這種方法並不是不好,只是我個人覺得沒 rust 那種返回值處理友善。
GC,java的GC發展20年了,go才這么點時間,gc鐵定不完善。所以我們仍然不能隨心所欲的寫代碼,不然在大請求量下面gc可能會卡頓整個服務。所以有時候,該用對象池,內存池的一定要用,雖然代碼丑了點,但好歹性能上去了。
1.4 開始 go 就是 100% 精確 GC 了,另外說到卡頓啊,完全和你怎麼用對象有關,能內聯絕不傳引用大部分場景是完全足夠的,這樣 gc 的影響程度會最低。實在想用池……只能說為啥不選 Java。
天生的並行支持,因為goroutine以及channel,用go寫分布式應用,寫並發程序異常的容易。沒有了蛋疼的callback導致的代碼邏輯割裂,代碼邏輯都是順序的。
這是有代價的,goroutine 的內存消耗計算(當然1.3還是1.4開始得到了很大的改善,內存最小值限制已經沒了),channel
跨線程帶來的性能損耗(跨線程鎖),還有對 goroutine 的控制力幾乎為 0
等。總之這種嘛,算不上是殺手級特性,大家都有,是方便了一點,但也有自己的弊端。比如我們用 go 吧,經常就比較蛋疼 spawn 出去的
goroutine 怎麼優美的 shutdown,反而有時候把事情做復雜化了。
性能,go的性能可能趕不上c,c++以及openresty,但真的也挺強悍的。在我們的項目中,現在單機就部署了一個go的進程,就完全能夠勝任以前200個python進程乾的事情,而且CPU和MEM佔用更低。
我不嚴謹的實測大概 gevent+py2 能達到同樣邏輯 go 實現的 30%~40%,pypy+tornado 能達到
80%~90%,混合了一些計算和連接處理什麼的。主要還是看業務場景吧,純粹的 CPU bound 當然是 go 好,純粹的 IO bound
你就是用 C 也沒用啊。
運維部署,直接編譯成二進制,扔到伺服器上面就成,比python需要安裝一堆的環境那是簡單的太多了。當然,如果有cgo,我們也需要將對應的動態庫給扔過去。
我們現在根據 glibc 所處的 host 版本不同有2套編譯環境,看上去是部署簡單了,編譯起來坑死你。另外雖然說 disk 便宜,這幾行代碼就幾M了,集群同步部署耗時在某些情況下還真會出簍子。
開發效率,雖然go是靜態語言,但我個人感覺開發效率真的挺高,直覺上面跟python不相上下。對於我個人來說,最好的
例子就是我用go快速開發了非常多的開源組件,譬如ledisdb,go-mysql等,而這些最開始的版本都是在很短的時間裡面完成的。對於我們項目來
說,我們也是用go在一個月就重構完成了第一個版本,並發布。
C. Python自己學習怎麼開始
這里根據行業變化和企業用人需求整理了一份Python全棧開發的學習路線,對於不知道從哪開始的初學者而言,可參考這份大綱來進行學習,希望可以幫助到你~
第一階段:專業核心基礎
階段目標:
1. 熟練掌握Python的開發環境與編程核心知識
2. 熟練運用Python面向對象知識進行程序開發
3. 對Python的核心庫和組件有深入理解
4. 熟練應用SQL語句進行資料庫常用操作
5. 熟練運用linux操作系統命令及環境配置
6. 熟練使用MySQL,掌握資料庫高級操作
7. 能綜合運用所學知識完成項目
知識點:
Python編程基礎、Python面向對象、Python高級進階、MySQL資料庫、Linux操作系統。
1、Python編程基礎,語法規則,函數與參數,數據類型,模塊與包,文件IO,培養扎實的Python編程基本功,同時對Python核心對象和庫的編程有熟練的運用。
2、Python面向對象,核心對象,異常處理,多線程,網路編程,深入理解面向對象編程,異常處理機制,多線程原理,網路協議知識,並熟練運用於項目中。
3、類的原理,MetaClass,下劃線的特殊方法,遞歸,魔術方法,反射,迭代器,裝飾器,UnitTest,Mock。深入理解面向對象底層原理,掌握Python開發高級進階技術,理解單元測試技術。
4、資料庫知識,範式,MySQL配置,命令,建庫建表,數據的增刪改查,約束,視圖,存儲過程,函數,觸發器,事務,游標,PDBC,深入理解資料庫管理系統通用知識及MySQL資料庫的使用與管理。為Python後台開發打下堅實基礎。
5、Linux安裝配置,文件目錄操作,VI命令,管理,用戶與許可權,環境配置,Docker,Shell編程Linux作為一個主流的伺服器操作系統,是每一個開發工程師必須掌握的重點技術,並且能夠熟練運用。
第二階段:PythonWEB開發
階段目標:
1. 熟練掌握Web前端開發技術,HTML,CSS,JavaScript及前端框架
2. 深入理解Web系統中的前後端交互過程與通信協議
3. 熟練運用Web前端和Django和Flask等主流框架完成Web系統開發
4. 深入理解網路協議,分布式,PDBC,AJAX,JSON等知識
5. 能夠運用所學知識開發一個MiniWeb框架,掌握框架實現原理
6. 使用Web開發框架實現貫穿項目
知識點:
Web前端編程、Web前端高級、Django開發框架、Flask開發框架、Web開發項目實戰。
1、Web頁面元素,布局,CSS樣式,盒模型,JavaScript,JQuery與Bootstrap掌握前端開發技術,掌握JQuery與BootStrap前端開發框架,完成頁面布局與美化。
2、前端開發框架Vue,JSON數據,網路通信協議,Web伺服器與前端交互熟練使用Vue框架,深入理解HTTP網路協議,熟練使用Swagger,AJAX技術實現前後端交互。
3、自定義Web開發框架,Django框架的基本使用,Model屬性及後端配置,Cookie與Session,模板Templates,ORM數據模型,Redis二級緩存,RESTful,MVC模型掌握Django框架常用API,整合前端技術,開發完整的WEB系統和框架。
4、Flask安裝配置,App對象的初始化和配置,視圖函數的路由,Request對象,Abort函數,自定義錯誤,視圖函數的返回值,Flask上下文和請求鉤子,模板,資料庫擴展包Flask-Sqlalchemy,資料庫遷移擴展包Flask-Migrate,郵件擴展包Flask-Mail。掌握Flask框架的常用API,與Django框架的異同,並能獨立開發完整的WEB系統開發。
第三階段:爬蟲與數據分析
階段目標:
1. 熟練掌握爬蟲運行原理及常見網路抓包工具使用,能夠對HTTP及HTTPS協議進行抓包分析
2. 熟練掌握各種常見的網頁結構解析庫對抓取結果進行解析和提取
3. 熟練掌握各種常見反爬機制及應對策略,能夠針對常見的反爬措施進行處理
4. 熟練使用商業爬蟲框架Scrapy編寫大型網路爬蟲進行分布式內容爬取
5. 熟練掌握數據分析相關概念及工作流程
6. 熟練掌握主流數據分析工具Numpy、Pandas和Matplotlib的使用
7. 熟練掌握數據清洗、整理、格式轉換、數據分析報告編寫
8. 能夠綜合利用爬蟲爬取豆瓣網電影評論數據並完成數據分析全流程項目實戰
知識點:
網路爬蟲開發、數據分析之Numpy、數據分析之Pandas。
1、爬蟲頁面爬取原理、爬取流程、頁面解析工具LXML,Beautifulfoup,正則表達式,代理池編寫和架構、常見反爬措施及解決方案、爬蟲框架結構、商業爬蟲框架Scrapy,基於對爬蟲爬取原理、網站數據爬取流程及網路協議的分析和了解,掌握網頁解析工具的使用,能夠靈活應對大部分網站的反爬策略,具備獨立完成爬蟲框架的編寫能力和熟練應用大型商業爬蟲框架編寫分布式爬蟲的能力。
2、Numpy中的ndarray數據結構特點、numpy所支持的數據類型、自帶的數組創建方法、算術運算符、矩陣積、自增和自減、通用函數和聚合函數、切片索引、ndarray的向量化和廣播機制,熟悉數據分析三大利器之一Numpy的常見使用,熟悉ndarray數據結構的特點和常見操作,掌握針對不同維度的ndarray數組的分片、索引、矩陣運算等操作。
3、Pandas裡面的三大數據結構,包括Dataframe、Series和Index對象的基本概念和使用,索引對象的更換及刪除索引、算術和數據對齊方法,數據清洗和數據規整、結構轉換,熟悉數據分析三大利器之一Pandas的常見使用,熟悉Pandas中三大數據對象的使用方法,能夠使用Pandas完成數據分析中最重要的數據清洗、格式轉換和數據規整工作、Pandas對文件的讀取和操作方法。
4、matplotlib三層結構體系、各種常見圖表類型折線圖、柱狀圖、堆積柱狀圖、餅圖的繪制、圖例、文本、標線的添加、可視化文件的保存,熟悉數據分析三大利器之一Matplotlib的常見使用,熟悉Matplotlib的三層結構,能夠熟練使用Matplotlib繪制各種常見的數據分析圖表。能夠綜合利用課程中所講的各種數據分析和可視化工具完成股票市場數據分析和預測、共享單車用戶群里數據分析、全球幸福指數數據分析等項目的全程實戰。
第四階段:機器學習與人工智慧
階段目標:
1. 理解機器學習相關的基本概念及系統處理流程
2. 能夠熟練應用各種常見的機器學習模型解決監督學習和非監督學習訓練和測試問題,解決回歸、分類問題
3. 熟練掌握常見的分類演算法和回歸演算法模型,如KNN、決策樹、隨機森林、K-Means等
4. 掌握卷積神經網路對圖像識別、自然語言識別問題的處理方式,熟悉深度學習框架TF裡面的張量、會話、梯度優化模型等
5. 掌握深度學習卷積神經網路運行機制,能夠自定義卷積層、池化層、FC層完成圖像識別、手寫字體識別、驗證碼識別等常規深度學習實戰項目
知識點:
1、機器學習常見演算法、sklearn數據集的使用、字典特徵抽取、文本特徵抽取、歸一化、標准化、數據主成分分析PCA、KNN演算法、決策樹模型、隨機森林、線性回歸及邏輯回歸模型和演算法。熟悉機器學習相關基礎概念,熟練掌握機器學習基本工作流程,熟悉特徵工程、能夠使用各種常見機器學習演算法模型解決分類、回歸、聚類等問題。
2、Tensorflow相關的基本概念,TF數據流圖、會話、張量、tensorboard可視化、張量修改、TF文件讀取、tensorflow playround使用、神經網路結構、卷積計算、激活函數計算、池化層設計,掌握機器學習和深度學習之前的區別和練習,熟練掌握深度學習基本工作流程,熟練掌握神經網路的結構層次及特點,掌握張量、圖結構、OP對象等的使用,熟悉輸入層、卷積層、池化層和全連接層的設計,完成驗證碼識別、圖像識別、手寫輸入識別等常見深度學習項目全程實戰。
D. Python開發測試學習選擇哪裡好
哪裡好自己選,只是注意廣告做得多的不一定好。
-------------
Python測試開發分享感悟
今天Zoom.Quiet在公司內部分享了對Python測試開發的一些感悟,TDD以及一些開源的Python測試的庫。由於一直在測試一線奮戰,我被做為特邀嘉賓來到現場。由於時間關系,最後我的分享沒有進行。我在這里說說對Zoom.Quiet演講內容的一些感想吧。
下面的鏈接是Zoom.Quiet的幻燈片:
http://py.kingsoft.net/s5/100826-PyTDD/
我打算分享的關於Python GUI測試的幻燈片:
http://py.kingsoft.net/s5/100826-PyTDD/py-gui-automation/
1. 重點強調了TDD測試先行的做法,以及新需求到來時進行迭代的測試驅動開發過程。
感想:「測試先行」的確是TDD的核心,同時,TDD還有其他一些理念,其實也很值得分享,比如:
編寫完測試案例後,用最小化或最精簡的代碼,讓測試案例剛剛好通過( just enough)。然後再繼續補充測試案例,測試案例可能失敗,繼而再修改代碼,讓新的測試案例剛剛好通過。之後一直重復這個過程,直到你再也寫不出一個測試案例,需要修改你的代碼。「just enough code」,我對於這點感觸比較深。一方面因為,我們幾乎沒有可能一次性寫出完全正確讓所有測試案例都通過的代碼,所以必定存在這個迭代的過程。另一方面,能很好的遵循YAGNI(You Are'nt Gonna Need It),避免了過度的設計。
測試案例是最好的注釋,同時也是最好的文檔。
2. 分享了大量Python的開源測試工具或庫。
感想:知道了很多自己不知道的東西,很有意義。
3. 「沒有測試案例的持續集成不是持續集成」
感想:說的太好了。同時也要自我反省一下,一直想將測試案例加入持續構建,一直都沒有去做~
4. 「測試的本質是什麼?」
感想:記得一本測試的書講過,測試的本質,就是「想盡一切辦法尋找軟體的缺陷!」。我覺得也是有道理的,所謂的「保證軟體的質量」,並不準確,至少,我可以舉一個反例,進行高效的代碼審查以及招聘最優秀的程序員,同樣也能保證軟體的質量,是不是軟體測試呢?有人說自動化測試不能發現新的缺陷,只能保證已發現的BUG不再重現。其實,只是我們理解的是保證BUG不重現,歸根結底,自動化測試案例一直重復的執行,還是為了找到軟體的缺陷,並且,是存在發現新缺陷的可能的。所以,別想了,軟體測試就是找BUG,直到你再也找不出來為止。(你找不出來並不意味著沒有)。
5. 「當你的代碼需要使用過多的Mock對象進行測試時,意味著你的代碼依賴過多,重構它吧」
「不可測的代碼,是需要使用大量的Mock對象的代碼」
「減少依賴,減少Mock對象的使用」
感想:對於這兩個觀點,我有一些不同意見。首先,除非你開發的是類似計算素數或是其他單一性很強的代碼,你不可能不依賴到文件系統,資料庫,以及網路。而一旦你的測試案例依賴於這三樣東西,你的測試案例就不再屬於單元測試,而是集成測試。除非你只把這部分代碼交給集成測試,不然你必然需要使用Mock對象。
當然,這里所說的Mock對象也是廣義的概念。嚴格來說,存在諸如:Spy,Fake,Stub,Mock等具有不同意義的東西。雖然只是概念上的理解,在實際測試過程中對測試案例的理解,還是很有意義的。
所以,我覺得,最不可測試的代碼,因為是連Mock的機會都不給的代碼。這樣的代碼我遇到過很多,特別是C++的代碼,我見過的C++程序員,對依賴注入都沒什麼概念。依賴注入,是為了減少對具體對象的依賴,同時,也提供了更好的可測性。允許使用Mock對象進行模擬。
關於Mock的爭論其實有很多,我也只是表達一點自己的看法。我也沒有那麼絕對,過度使用Mock,我也是不推薦的。
6. 有人提問:「TDD對可測性的幫助有多大?」
我的回答:很大,非常大。當你寫過別人代碼的測試案例的時候你就會知道,假如一個傢伙從來不寫測試案例,他的代碼測試起來會非常痛苦。假如另一個傢伙自己就會寫一些測試案例測試自己的代碼,在寫測試代碼的過程中,其實就已經是在不斷的重構,使得代碼更具可測性的過程。所以,這樣的代碼的可測性會強很多。
7. 關於我自個開發的KWinAuto自動化GUI測試框架
說明:其實這個是我們內部使用的一個GUI測試框架。為了讓名字更好聽,我臨時修改了名字,因為靈感和一些東西來自開源的PyWinAuto,所以,我索性取了個名,叫KWinAuto。這個框架主要是非常簡單的處理了常見的Windows控制項的操作,並且是為我們自己實際測試量身打造的這么一個庫。離最終開源出來讓大家分享還是有一些距離,所以,就先不放出來了,大家就從我的幻燈片里先了解一下吧。
E. Python unittest的mock模塊怎麼理解side
在Python2.x 中 mock是一個單獨模塊,需要單獨安裝。
> pip install -U mock
在Python3.x中,mock已經被集成到了unittest單元測試框架中,所以,可以直接使用。
F. python 開發經驗怎麼xie
當我開始學習Python的時候,有些事我希望我一早就知道。我花費了很多時間才學會這些東西。我想要把這些重點都編纂到一篇文章當中。這篇文章的目標讀者,是剛剛開始學習Python語言的有經驗的程序員,想要跳過前幾個月研究Python使用的那些他們已經在用的類似工具。包管理和標准工具這兩節對於初學者來說同樣很有幫助。
我的經驗主要基於Python 2.7,但是大多數的工具對任何版本都有效。
如果你從來沒有使用過Python,我強烈建議你閱讀Python introction,因為你需要知道基本的語法和類型。
包管理
Python世界最棒的地方之一,就是大量的第三方程序包。同樣,管理這些包也非常容易。按照慣例,會在 requirements.txt 文件中列出項目所需要的包。每個包佔一行,通常還包含版本號。這里有一個例子,本博客使用Pelican:
1
2
3
pelican==3.3
Markdown
pelican-extended-sitemap==1.0.0
Python 程序包有一個缺陷是,它們默認會進行全局安裝。我們將要使用一個工具,使我們每個項目都有一個獨立的環境,這個工具叫virtualenv。我們同樣要安裝一個更高級的包管理工具,叫做pip,他可以和virtualenv配合工作。
首先,我們需要安裝pip。大多數python安裝程序已經內置了easy_install(python默認的包管理工具),所以我們就使用easy_install pip來安裝pip。這應該是你最後一次使用easy_install 了。如果你並沒有安裝easy_install ,在linux系統中,貌似從python-setuptools 包中可以獲得。
如果你使用的Python版本高於等於3.3, 那麼Virtualenv 已經是標准庫的一部分了,所以沒有必要再去安裝它了。
下一步,你希望安裝virtualenv和virtualenvwrapper。Virtualenv使你能夠為每個項目創造一個獨立的環境。尤其是當你的不同項目使用不同版本的包時,這一點特別有用。Virtualenv wrapper 提供了一些不錯的腳本,可以讓一些事情變得容易。
1
sudo pip install virtualenvwrapper
當virtualenvwrapper安裝後,它會把virtualenv列為依賴包,所以會自動安裝。
打開一個新的shell,輸入mkvirtualenv test 。如果你打開另外一個shell,則你就不在這個virtualenv中了,你可以通過workon test 來啟動。如果你的工作完成了,可以使用deactivate 來停用。
IPython
IPython是標准Python互動式的編程環境的一個替代品,支持自動補全,文檔快速訪問,以及標准互動式編程環境本應該具備的很多其他功能。
當你處在一個虛擬環境中的時候,可以很簡單的使用pip install ipython 來進行安裝,在命令行中使用ipython 來啟動
另一個不錯的功能是」筆記本」,這個功能需要額外的組件。安裝完成後,你可以使用ipython notebook,而且會有一個不錯的網頁UI,你可以創建筆記本。這在科學計算領域很流行。
測試
我推薦使用nose或是py.test。我大部分情況下用nose。它們基本上是類似的。我將講解nose的一些細節。
這里有一個人為創建的可笑的使用nose進行測試的例子。在一個以test_開頭的文件中的所有以test_開頭的函數,都會被調用:
1
2
def test_equality():
assert True == False
不出所料,當運行nose的時候,我們的測試沒有通過。
1
2
3
4
5
6
7
8
9
10
11
12
13
(test)jhaddad@jons-mac-pro ~VIRTUAL_ENV/src$ nosetests
F
======================================================================
FAIL: test_nose_example.test_equality
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/jhaddad/.virtualenvs/test/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
self.test(*self.arg)
File "/Users/jhaddad/.virtualenvs/test/src/test_nose_example.py", line 3, in test_equality
assert True == False
AssertionError
----------------------------------------------------------------------
nose.tools中同樣也有一些便捷的方法可以調用
1
2
3
from nose.tools import assert_true
def test_equality():
assert_true(False)
如果你想使用更加類似JUnit的方法,也是可以的:
1
2
3
4
5
6
7
8
9
10
from nose.tools import assert_true
from unittest import TestCase
class ExampleTest(TestCase):
def setUp(self): # setUp & tearDown are both available
self.blah = False
def test_blah(self):
self.assertTrue(self.blah)
開始測試:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
(test)jhaddad@jons-mac-pro ~VIRTUAL_ENV/src$ nosetests
F
======================================================================
FAIL: test_blah (test_nose_example.ExampleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/jhaddad/.virtualenvs/test/src/test_nose_example.py", line 11, in test_blah
self.assertTrue(self.blah)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 1 test in 0.003s
FAILED (failures=1)
卓越的Mock庫包含在Python 3 中,但是如果你在使用Python 2,可以使用pypi來獲取。這個測試將進行一個遠程調用,但是這次調用將耗時10s。這個例子顯然是人為捏造的。我們使用mock來返回樣本數據而不是真正的進行調用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import mock
from mock import patch
from time import sleep
class Sweetness(object):
def slow_remote_call(self):
sleep(10)
return "some_data" # lets pretend we get this back from our remote api call
def test_long_call():
s = Sweetness()
result = s.slow_remote_call()
assert result == "some_data"
當然,我們的測試需要很長的時間。
1
2
3
4
5
(test)jhaddad@jons-mac-pro ~VIRTUAL_ENV/src$ nosetests test_mock.py
Ran 1 test in 10.001s
OK
太慢了!因此我們會問自己,我們在測試什麼?我們需要測試遠程調用是否有用,還是我們要測試當我們獲得數據後要做什麼?大多數情況下是後者。讓我們擺脫這個愚蠢的遠程調用吧:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import mock
from mock import patch
from time import sleep
class Sweetness(object):
def slow_remote_call(self):
sleep(10)
return "some_data" # lets pretend we get this back from our remote api call
def test_long_call():
s = Sweetness()
with patch.object(s, "slow_remote_call", return_value="some_data"):
result = s.slow_remote_call()
assert result == "some_data"
好吧,讓我們再試一次:
1
2
3
4
5
6
(test)jhaddad@jons-mac-pro ~VIRTUAL_ENV/src$ nosetests test_mock.py
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
好多了。記住,這個例子進行了荒唐的簡化。就我個人來講,我僅僅會忽略從遠程系統的調用,而不是我的資料庫調用。
nose-progressive是一個很好的模塊,它可以改善nose的輸出,讓錯誤在發生時就顯示出來,而不是留到最後。如果你的測試需要花費一定的時間,那麼這是件好事。
pip install nose-progressive 並且在你的nosetests中添加--with-progressive
調試
iPDB是一個極好的工具,我已經用它查出了很多匪夷所思的bug。pip install ipdb 安裝該工具,然後在你的代碼中import ipdb; ipdb.set_trace(),然後你會在你的程序運行時,獲得一個很好的互動式提示。它每次執行程序的一行並且檢查變數。
python內置了一個很好的追蹤模塊,幫助我搞清楚發生了什麼。這里有一個沒什麼用的python程序:
1
2
3
a = 1
b = 2
a = b
這里是對這個程序的追蹤結果:
1
2
3
4
5
6
7
(test)jhaddad@jons-mac-pro ~VIRTUAL_ENV/src$ python -m trace --trace tracing.py 1 ?
--- molename: tracing, funcname: <mole>
tracing.py(1): a = 1
tracing.py(2): b = 2
tracing.py(3): a = b
--- molename: trace, funcname: _unsettrace
trace.py(80): sys.settrace(None)
當你想要搞清楚其他程序的內部構造的時候,這個功能非常有用。如果你以前用過strace,它們的工作方式很相像
在一些場合,我使用pycallgraph來追蹤性能問題。它可以創建函數調用時間和次數的圖表。
最後,objgraph對於查找內存泄露非常有用。這里有一篇關於如何使用它查找內存泄露的好文。
Gevent
Gevent 是一個很好的庫,封裝了Greenlets,使得Python具備了非同步調用的功能。是的,非常棒。我最愛的功能是Pool,它抽象了非同步調用部分,給我們提供了可以簡單使用的途徑,一個非同步的map()函數:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from gevent import monkey
monkey.patch_all()
from time import sleep, time
def fetch_url(url):
print "Fetching %s" % url
sleep(10)
print "Done fetching %s" % url
from gevent.pool import Pool
urls = ["http://test.com", "http://bacon.com", "http://eggs.com"]
p = Pool(10)
start = time()
p.map(fetch_url, urls)
print time() - start
非常重要的是,需要注意這段代碼頂部對gevent monkey進行的補丁,如果沒有它的話,就不能正確的運行。如果我們讓Python連續調用 fetch_url 3次,通常我們期望這個過程花費30秒時間。使用gevent:
1
2
3
4
5
6
7
8
(test)jhaddad@jons-mac-pro ~VIRTUAL_ENV/src$ python g.py
Fetching http://test.com
Fetching http://bacon.com
Fetching http://eggs.com
Done fetching http://test.com
Done fetching http://bacon.com
Done fetching http://eggs.com
10.001791954
如果你有很多資料庫調用或是從遠程URLs獲取,這是非常有用的。我並不是很喜歡回調函數,所以這一抽象對我來說效果很好。
G. python mock和patch的區別
patch 函數會返回一個 mock 內部的類實例,這個類是class _patch