怎麼用python進行測試?
我是個初級測試人員,看到大牛們經驗分享life is short, test in Python。問問怎麼把python用於測試中?比如測試網頁,測試介面?最好能舉個好用的框架或者舉幾個栗子。
python在測試方面簡直是無孔不入,從單元到介面,從自動化到性能...
性能測試工具nGrinder介紹?china-testing.github.io這個可以用java寫的python即jython做性能測試,類似的還有:
使用jython進行dubbo介面及ngrinder性能測試?china-testing.github.iopython本身有性能測試工具或可以開發性能測試工具
性能測試工具locustio?www.jianshu.com安全測試的工具很多是python寫的,參考下:
滲透測試工具簡介2入侵工具?www.jianshu.com
selenium等可以做web自動化測試,appium基於selenium可以做手機端自動化測試。
selenium自動化測試工具python筆試面試項目實戰7 書籍下載?www.jianshu.compython還有pytest等功能強大的單元測試框架,介面,自動化測試都經常使用它做測試執行。
自動化測試框架pytest教程 - 目錄?china-testing.github.io自動化測試框架pytest教程 - 目錄
自動化測試框架pytest教程 - 目錄?china-testing.github.io軟體測試工具書籍與面試題匯總下載(持續更新)?www.jianshu.com介面測試:
python工具庫介紹-requests:人性化的HTTP?www.jianshu.com介面協議工具thrift1快速入門?www.jianshu.com還可以開發測試平臺:
flask工具構建自動化測試平臺1-hello?www.jianshu.compython是軟體測試使用最廣泛的語言,太多東東可以用於測試了, 還有海量的測試開發庫參見:
https://github.com/china-testing/python-api-tesing?github.com歡迎點贊,並關注
知乎用戶?www.zhihu.com謝謝
看了題主提的問題, 看來要走的路還挺長啊........
首先你要去學習Python基礎, 然後自動化測試使用Python+Selenium, 介面測試使用Python+Requests+Unittest框架.
這裡有一些資料, 可以分享給你哈
祝自動化測試之路順利哈
先練好基本功,再去學大牛。
大牛們的經驗並不是說Python絕對的好,而是在大牛們的經歷中,跟其他語言或工具相比,覺得Python特別好用。問題就來了,你要處理的問題,跟大牛們一樣嗎?
如你所說的測試網頁、測試介面,都不是直接用Python寫代碼去測的,都是需要靠工具、靠框架、靠庫。自己搜索一下就有,例如:PythonTestingToolsTaxonomy這裡首先需要澄清幾個概念,理清思路。
我們從你說的介面測試和web ui測試來入手,這是測試需求和手段。實現某種測試手段的,是某一種語言的一個基礎類庫。
例如,http介面收發可以使用python的requests庫,而web ui元素定位和操作可以用selenium的web driver。
但實際上其他語言也可能有等價的類庫,例如java就有http request和response庫,selenium是支持大部分語言的。
使用這樣的類庫進行一定的action,把結果進行verify,這就是一條測試用例,或者叫做測試腳本。
而測試框架是在做什麼呢?
測試框架可以幫助你編排測試用例,處理公用方法,變數,處理數據準備和清理,日誌,報告等等。例如,python的pytest就是最廣泛使用的python測試框架。
其他語言也有類似的測試框架,例如java的testng,golang的ginkgo。
同時,一個測試框架可以跟測試手段,以及基礎類庫無關。也就是說pytest既可以做介面測試,也可以做ui測試,也可以做性能測試,甚至可以在一套框架裡面並存。
測試框架是幫助你組織測試的,沒有測試框架,你自己寫一個main函數作為入口的測試腳本,顯然也是可以的。
所以,技術選型的時候,要兼顧兩條思維路線。
第一條路線:
你要測什麼
你要用什麼手段測
你所選擇的語言,是否有好用的對應的基礎類庫,能實現這個測試手段
第二條路線:
你要怎麼測
你是否有複雜的測試組織需求,例如,並發,串列,數據準備和清理,參數化,報告等
你所選的語言,是否具備滿足上述能力的測試框架
推薦的工具或框架,我加粗寫在上面了
python是現在相對交火的一門語言,多用於軟體自動化測試,但是像題主這個情況,個人建議你還是先把python學好學精再去考慮用它去經行測試,可以去聽聽相關的公開課,讀讀相關的書籍
發佈於 2018-10-10繼續瀏覽內容之前CSDN編譯過一篇文章,貼出來,希望對你有幫助。
近年來測試驅動開發(TDD)受到越來越多的關注。這是一個持續改進的過程,能從一開始就形成規範,幫助提高代碼質量。這是切實可行的而非天馬行空的。
TDD的全過程是非常簡單的。藉助TDD,代碼質量會得到提升,同時可以讓你保持清晰的思路。TDD與敏捷開發可謂強強聯合,特別是在進行結對編程的時候。本文主要介紹了TDD的核心概念,還有結合nosetest單元測試包進行Python示例簡析。另外還會介紹一些Python備用包。
TDD是什麼?
使用該方法可讓你少走前人的彎路
顧名思義,TDD即進行編程時先把測試部分寫好,當發現不能通過時,再進行編程以使測試通過。然後在這基礎上適當地調整測試代碼以實現更多功能,最後再編寫代碼使之實現。
TDD看起來非常像一個環,首先是要不斷調整測試代碼,然後是編碼,改進,最後直至完成。先實現測試部分的做法會使你自然養成把問題放在首位的思維習慣。當真正去構建代碼時,就不得不想清楚該如何把設計做好;比方說,該方法有何返回值?當遇到異常時該怎麼辦?諸如此類。
以這樣的方式進行開發,意味著要想出不同的代碼實現路徑,並在測試中進行實踐。這樣做可使你少走前人的彎路:陷入一個問題後寫出毫不相關的解決方案。
該過程可描述如下:
- 寫出一個缺陷單元測試
- 使該單元測試通過
- 重構
與敏捷開發結合
TDD與敏捷開發並行不悖甚至1+1遠大於2,這裡指的是代碼質量而不是數量。
「這意味著結對雙方都會參與其中,著重於當前工作,然後在每個環節進行互檢。」
然而在結對編程時TDD是單獨進行的。如果能把雙方的開發流程混合好,互相都能理解就最好不過了。例如,其中一人寫出單元測試,當測試通過後,另外一人可以編寫不同的測試以之通過。
任何時候結對雙方都可以互換角色,每半天或天。這意味著結對雙方都會參與其中,每人都把精力放在當前任務上,然後在每個環節進行交叉互檢。這難道不是一個雙贏的做法嗎?
TDD也可以是行為驅動開發過程中的組成部分,同樣地,首先寫出測試,只不過這裡指的是接受測試。這樣有助於把工作從頭到尾都保持規範。
單元測試語法
進行單元測試時,使用到的Python方法如下:
- assert: 編寫個人聲明的基本方式
- assertEqual(a,b):檢查a和b的是否等價
- assertNotEqual(a,b):檢查a和b的是否非等價
- assertIn(a,b):檢查是否存在b中
- assertNotIn(a,b): 檢查是否不存在b中
- assertFalse(a):檢查a的值是否為False
- assertTrue(a):檢查a的值是否為Ture
- assertIsInstance(a,TYPE):檢查a是否為「TYPE」類型
- assertRaises(ERROR,a,args):以參數args調用a時,檢查是否會出現ERROR
以上是實際當中使用頻率最高的方法,更多的方法請查閱Python單元測試文檔。
安裝並使用Python Nose
進行下面的練習前,請把nosetest測試運行包安裝好。使用標準pip語句進行安裝是最直接的做法。此外在項目中使用VirtualEnv(Python虛擬環境)也是不錯的做法,因為它可確保所有包在不同項目中是獨立的。假如對pip或VirtualEnv瞭解不多,不妨先查閱相關文檔:VirtualEnv,PIP。
pip語句十分簡潔:
"pip install nose"
安裝完成後,可以執行單個測試文件
$ nosetests example_unit_test.py
或者可以直接執行文件夾中的文件組
$ nosetests /path/to/tests
這裡要注意的是每個測試方法都應以「test_」為開頭,這樣nosetest運行機才能正確識別出目標測試文件。
可選參數
下面介紹幾個有用的命令行參數:
- -v:輸出更多信息,包括正在執行的測試文件名
- -s或-nocapture:進行PRINT語句輸出,一般情況下這是隱藏的。開啟後可方便調試。
- --nologcapture:輸出日誌信息
- --rednose:一個可選插件,請點擊這裡下載,輸出帶顏色的輸出信息。
- --tags=TAGS:指定要執行的測試文件,而不是整個測試文件組
實例分析和測試驅動方法
接下來會結合一個簡單的計算器類例子例如相加/相減,來講述Python單元測試和TDD本概念。對於add相加功能,會嘗試編寫一個缺陷測試。
在一個空白項目中,首先創建兩個python包app和test。然後在每個文件裏建立兩個名為_init_.py空白文件。這是Phthon工程的標準結構,完成後可以擁有一個可導入的文件結構。如果需要了解更多有關文檔架構的信息,請查閱Python包說明文檔。 在測試目錄裏創建一個test_calulator.py文件,其代碼如下:
import unittest
class TddInPythonExample(unittest.TestCase):def test_calculator_add_method_returns_correct_result(self):calc = Calculator()
result = calc.add(2,2)self.assertEqual(4, result)
說明:
- 首先,從Python標準庫裏導入標準的unittest模塊
- 接著,創建一個含有不同測試用例的類
- 最後,創建以「test_」為開頭的一個測試方法
完成後可著手編寫測試代碼了。執行方法前要先對計算器進行初始化,初始化完成後便可調用add方法,並把結果存入變數result中。完成後,使用unittest的assertEqual方法來確保add方法正常執行。
現在可以啟動nosetest來執行測試文件了。代碼如下:
if __name__ == __main__:
unittest.main()
標準的Python文件執行方式為$ python test_calculator.py,相比之下本文使用的nosetests方法功能更豐富,例如可以運行目錄中的全部測試文件。
$ nosetests test_calculator.py
E======================================================================ERROR: test_calculator_add_method_returns_correct_result (test.test_calculator.TddInPythonExample)
----------------------------------------------------------------------Traceback (most recent call last):File "/Users/user/PycharmProjects/tdd_in_python/test/test_calculator.py", line 6, in test_calculator_add_method_returns_correct_resultcalc = Calculator()NameError: global name Calculator is not defined----------------------------------------------------------------------Ran 1 test in 0.001sFAILED (errors=1)
運行後可見出錯的原因是沒有導入Caculator。因為還沒有創建呢!創建的方法是在app目錄下建立calculator.py文件,然後導入:
class Calculator(object):
def add(self, x, y):pass[py] view plaincopyimport unittestfrom app.calculator import Calculatorclass TddInPythonExample(unittest.TestCase):def test_calculator_add_method_returns_correct_result(self):calc = Calculator()result = calc.add(2,2)self.assertEqual(4, result)if __name__ == __main__:unittest.main()
把Caculator構建好之後,再次運行看會出現什麼結果:
$ nosetests test_calculator.py
F======================================================================FAIL: test_calculator_add_method_returns_correct_result (test.test_calculator.TddInPythonExample)----------------------------------------------------------------------Traceback (most recent call last):File "/Users/user/PycharmProjects/tdd_in_python/test/test_calculator.py", line 9, in test_calculator_add_method_returns_correct_resultself.assertEqual(4, result)AssertionError: 4 != None----------------------------------------------------------------------Ran 1 test in 0.001sFAILED (failures=1)
很明顯,add方法返回了錯誤的值,因為還沒有為它指定行為。幸好nosetest會指出出錯的位置,方便進行修改。稍作改動後,測試便可通過了:
class Calculator(object):
def add(self, x, y):return x+y[py] view plaincopy$ nosetests test_calculator.py.----------------------------------------------------------------------Ran 1 test in 0.000sOK
雖然通過了,但是圍繞該方法還可以做更多的工作。
沉迷於某個案例很容易造成短視
如果進行非數字型數據相加會導致什麼後果呢?事實上Python是允許字元串或其它類型進行相加的,但在我們的例子裏不允許。接著嘗試就這個例子加入另一個缺陷測試,然後使用assertRaises方法來判斷是否有異常拋出:
import unittest
from app.calculator import Calculatorclass TddInPythonExample(unittest.TestCase):def setUp(self):self.calc = Calculator()def test_calculator_add_method_returns_correct_result(self):result = self.calc.add(2, 2)self.assertEqual(4, result)def test_calculator_returns_error_message_if_both_args_not_numbers(self):self.assertRaises(ValueError, self.calc.add, two, three)if __name__ == __main__:unittest.main()
以上代碼中,檢查了是否引起了ValueError錯誤,其實還可以進行更多的檢測,不過在這裡不作深入講述。此外,setup()方法用於推入計算對象。下面再看看nosetest會反饋什麼信息:
$ nosetests test_calculator.py
.F======================================================================FAIL: test_calculator_returns_error_message_if_both_args_not_numbers (test.test_calculator.TddInPythonExample)----------------------------------------------------------------------Traceback (most recent call last):File "/Users/user/PycharmProjects/tdd_in_python/test/test_calculator.py", line 15, in test_calculator_returns_error_message_if_both_args_not_numbersself.assertRaises(ValueError, self.calc.add, two, three)AssertionError: ValueError not raised----------------------------------------------------------------------Ran 2 tests in 0.001sFAILED (failures=1)
顯然nosetests告訴我們ValueError沒有被拋出。現在我們有了一個新的缺陷測試,接著嘗試編碼進行解決:
class Calculator(object):
def add(self, x, y):number_types = (int, long, float, complex)if isinstance(x, number_types) and isinstance(y, number_types):return x + yelse:raise ValueError
代碼中使用了isinstance方法是為了確保輸入的是數字型數據。
由於兩個變數的類型有多種組合,為了進行完整的測試,所以需要把可能出現的組合進行統籌並進行處理:
import unittest
from app.calculator import Calculatorclass TddInPythonExample(unittest.TestCase):def setUp(self):self.calc = Calculator()def test_calculator_add_method_returns_correct_result(self):result = self.calc.add(2, 2)self.assertEqual(4, result)def test_calculator_returns_error_message_if_both_args_not_numbers(self):self.assertRaises(ValueError, self.calc.add, two, three)def test_calculator_returns_error_message_if_x_arg_not_number(self):self.assertRaises(ValueError, self.calc.add, two, 3)def test_calculator_returns_error_message_if_y_arg_not_number(self):self.assertRaises(ValueError, self.calc.add, 2, three)if __name__ == __main__:unittest.main()
至此我們可以運行所有的測試了,所要實現的需求也都滿足了。
其它的單元測試包
py.test
pytest的作用與nosetest類似,不過可以在單獨的區域裏輸出信息,這意味著能夠使我們很快地看清楚命令行中出現的列印信息。這對於只運行單個測試的情況是很有用的。
$ nosetests test_calculator.py
....----------------------------------------------------------------------Ran 4 tests in 0.001sOK
安裝pytest的方式與nosetest差不多,命令是$ pip install pytes。執行的命令是$ pip install pytes或者指定要執行的測試文件$ py.test test/calculator_tests.py。
$ py.test test/test_calculator.py
================================================================= test session starts =================================================================platform darwin -- Python 2.7.6 -- py-1.4.26 -- pytest-2.6.4collected 4 itemstest/test_calculator.py ....============================================================== 4 passed in 0.02 seconds ===============================================================
pytest運行後的結果如下。註:只有代碼含有錯誤或異常的情況下,pytest才會進行輸出。
$ py.test test/test_calculator.py
================================================================= test session starts =================================================================platform darwin -- Python 2.7.6 -- py-1.4.26 -- pytest-2.6.4collected 4 itemstest/test_calculator.py F...====================================================================== FAILURES =======================================================================________________________________________ TddInPythonExample.test_calculator_add_method_returns_correct_result _________________________________________self = &def test_calculator_add_method_returns_correct_result(self):result = self.calc.add(3, 2)&> self.assertEqual(4, result)E AssertionError: 4 != 5test/test_calculator.py:11: AssertionError---------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------X value is: 3Y value is: 2Result is 5========================================================= 1 failed, 3 passed in 0.03 seconds ==========================================================
單元測試
如果不想安裝額外的包並想保持一個純凈的標準庫結構,使用Python內建的unittest單元測試包是不錯的選擇。其使用方法如下:
if __name__ == __main__:
unittest.main()使用python calculator_tests.py執行後,看會得到什麼結果:[py] view plaincopy$ python test/test_calculator.py....----------------------------------------------------------------------Ran 4 tests in 0.004sOK
使用PDB進行調試
以TDD方式開發,經常會遇到來自代碼或測試的問題。有時這些錯誤又是比較隱蔽的。因此,需要配合使用高明的調試技術。
以TDD方式進行開發出現問題時可能難以發現
幸運地,有不少的辦法來解決這些問題。其中最簡單的方式是透過增添print語句實現「斷點」輸出。
結合print語句進行調試
加法通過後,可以嘗試進行減法調試。把app/calculator.py中的add部分代碼作如下改動:
class Calculator(object):
def add(self, x, y):number_types = (int, long, float, complex)if isinstance(x, number_types) and isinstance(y, number_types):return x - yelse:raise ValueError
這裡不妨嘗試使用print語句進行輸出,來監視值是怎樣變化的。
class Calculator(object):
def add(self, x, y):number_types = (int, long, float, complex)if isinstance(x, number_types) and isinstance(y, number_types):print X is: {}.format(x)print Y is: {}.format(y)result = x - yprint Result is: {}.format(result)return resultelse:raise ValueError
現在可以使用nosetest來執行並查看結果,可見這樣的工整輸出結構,對調試是十分有幫助的。
$ nosetests test/test_calculator.py
F...======================================================================FAIL: test_calculator_add_method_returns_correct_result (test.test_calculator.TddInPythonExample)----------------------------------------------------------------------Traceback (most recent call last):File "/Users/user/PycharmProjects/tdd_in_python/test/test_calculator.py", line 11, in test_calculator_add_method_returns_correct_resultself.assertEqual(4, result)AssertionError: 4 != 0-------------------- &>&> begin captured stdout &X is: 2Y is: 2Result is: 0--------------------- &>&> end captured stdout &----------------------------------------------------------------------Ran 4 tests in 0.002sFAILED (failures=1)
PDB進階調試
如果遇到更複雜的調試環節,僅僅依靠print語句是不夠的。其中最經常使用的進階調試工具是pdb(Python Debugger)。該工具包含在標準庫中,使用的時候只需加入一行代碼到「斷點」位置。請看下面的代碼:
class Calculator(object):
def add(self, x, y):number_types = (int, long, float, complex)if isinstance(x, number_types) and isinstance(y, number_types):import pdb; pdb.set_trace()return x - yelse:raise ValueError
請注意,如果使用nosetest執行測試,請務必使用-s標記,否則nosetest會繼續對輸出進行抓取,這樣會使pdb無法正常運行。如果是使用unittest或pytest則無需這樣做。
如果測試停止並有pdb提示,請使用list命令來進行當前代碼定位。
$ nosetests -s
&> /Users/user/PycharmProjects/tdd_in_python/app/calculator.py(7)add()-&> return x - y(Pdb) list2 def add(self, x, y):3 number_types = (int, long, float, complex)45 if isinstance(x, number_types) and isinstance(y, number_types):6 import pdb; pdb.set_trace()7 -&> return x - y8 else:9 raise ValueError[EOF](Pdb)
出現提示後是可以進行交互操作的,比方說想在這個時候檢閱x和y的值:
(Pdb) x
2(Pdb) y2
如果想了解更多命令,可以鍵入 help來查看。經常使用的命令如下所示:
- n: 步進到下個執行
- list: 顯示當前位置
- args: 顯示在當前執行點上用到的變數
- continue:運行代碼直至結束
- jump &: 運行並跳轉到行號位置
- quit/exit:停止pdb
寫在最後
TDD模式十分有趣同時能幫助提高代碼質量。不論是大型團隊還是個人開發,TDD都可運用其中。此外,成功的缺陷測試設計是非常有滿足感的。所以,不妨從今天起嘗試把TDD引入到日常工作中,親身體驗試驗前後會有什麼變化。
發佈於 2018-10-16繼續瀏覽內容怎麼做python自動化,清楚下python在那些層次能做:
不管做ui的python+selenium+unittest、python+appium+unittest;
還是做介面的python+requests
還是做平臺開發的python有flask和django
之前CSDN編譯過一篇文章,貼出來,希望對你有幫助。
近年來測試驅動開發(TDD)受到越來越多的關注。這是一個持續改進的過程,能從一開始就形成規範,幫助提高代碼質量。這是切實可行的而非天馬行空的。
TDD的全過程是非常簡單的。藉助TDD,代碼質量會得到提升,同時可以讓你保持清晰的思路。TDD與敏捷開發可謂強強聯合,特別是在進行結對編程的時候。本文主要介紹了TDD的核心概念,還有結合nosetest單元測試包進行Python示例簡析。另外還會介紹一些Python備用包。
TDD是什麼?
使用該方法可讓你少走前人的彎路
顧名思義,TDD即進行編程時先把測試部分寫好,當發現不能通過時,再進行編程以使測試通過。然後在這基礎上適當地調整測試代碼以實現更多功能,最後再編寫代碼使之實現。
TDD看起來非常像一個環,首先是要不斷調整測試代碼,然後是編碼,改進,最後直至完成。先實現測試部分的做法會使你自然養成把問題放在首位的思維習慣。當真正去構建代碼時,就不得不想清楚該如何把設計做好;比方說,該方法有何返回值?當遇到異常時該怎麼辦?諸如此類。
以這樣的方式進行開發,意味著要想出不同的代碼實現路徑,並在測試中進行實踐。這樣做可使你少走前人的彎路:陷入一個問題後寫出毫不相關的解決方案。
該過程可描述如下:
- 寫出一個缺陷單元測試
- 使該單元測試通過
- 重構
與敏捷開發結合
TDD與敏捷開發並行不悖甚至1+1遠大於2,這裡指的是代碼質量而不是數量。
「這意味著結對雙方都會參與其中,著重於當前工作,然後在每個環節進行互檢。」
然而在結對編程時TDD是單獨進行的。如果能把雙方的開發流程混合好,互相都能理解就最好不過了。例如,其中一人寫出單元測試,當測試通過後,另外一人可以編寫不同的測試以之通過。
任何時候結對雙方都可以互換角色,每半天或天。這意味著結對雙方都會參與其中,每人都把精力放在當前任務上,然後在每個環節進行交叉互檢。這難道不是一個雙贏的做法嗎?
TDD也可以是行為驅動開發過程中的組成部分,同樣地,首先寫出測試,只不過這裡指的是接受測試。這樣有助於把工作從頭到尾都保持規範。
單元測試語法
進行單元測試時,使用到的Python方法如下:
- assert: 編寫個人聲明的基本方式
- assertEqual(a,b):檢查a和b的是否等價
- assertNotEqual(a,b):檢查a和b的是否非等價
- assertIn(a,b):檢查是否存在b中
- assertNotIn(a,b): 檢查是否不存在b中
- assertFalse(a):檢查a的值是否為False
- assertTrue(a):檢查a的值是否為Ture
- assertIsInstance(a,TYPE):檢查a是否為「TYPE」類型
- assertRaises(ERROR,a,args):以參數args調用a時,檢查是否會出現ERROR
以上是實際當中使用頻率最高的方法,更多的方法請查閱Python單元測試文檔。
安裝並使用Python Nose
進行下面的練習前,請把nosetest測試運行包安裝好。使用標準pip語句進行安裝是最直接的做法。此外在項目中使用VirtualEnv(Python虛擬環境)也是不錯的做法,因為它可確保所有包在不同項目中是獨立的。假如對pip或VirtualEnv瞭解不多,不妨先查閱相關文檔:VirtualEnv,PIP。
pip語句十分簡潔:
"pip install nose"
安裝完成後,可以執行單個測試文件
$ nosetests example_unit_test.py
或者可以直接執行文件夾中的文件組
$ nosetests /path/to/tests
這裡要注意的是每個測試方法都應以「test_」為開頭,這樣nosetest運行機才能正確識別出目標測試文件。
可選參數
下面介紹幾個有用的命令行參數:
- -v:輸出更多信息,包括正在執行的測試文件名
- -s或-nocapture:進行PRINT語句輸出,一般情況下這是隱藏的。開啟後可方便調試。
- --nologcapture:輸出日誌信息
- --rednose:一個可選插件,請點擊這裡下載,輸出帶顏色的輸出信息。
- --tags=TAGS:指定要執行的測試文件,而不是整個測試文件組
實例分析和測試驅動方法
接下來會結合一個簡單的計算器類例子例如相加/相減,來講述Python單元測試和TDD本概念。對於add相加功能,會嘗試編寫一個缺陷測試。
在一個空白項目中,首先創建兩個python包app和test。然後在每個文件裏建立兩個名為_init_.py空白文件。這是Phthon工程的標準結構,完成後可以擁有一個可導入的文件結構。如果需要了解更多有關文檔架構的信息,請查閱Python包說明文檔。 在測試目錄裏創建一個test_calulator.py文件,其代碼如下:
import unittest
class TddInPythonExample(unittest.TestCase):def test_calculator_add_method_returns_correct_result(self):calc = Calculator()result = calc.add(2,2)self.assertEqual(4, result)
說明:
- 首先,從Python標準庫裏導入標準的unittest模塊
- 接著,創建一個含有不同測試用例的類
- 最後,創建以「test_」為開頭的一個測試方法
完成後可著手編寫測試代碼了。執行方法前要先對計算器進行初始化,初始化完成後便可調用add方法,並把結果存入變數result中。完成後,使用unittest的assertEqual方法來確保add方法正常執行。
現在可以啟動nosetest來執行測試文件了。代碼如下:
if __name__ == __main__:
unittest.main()
標準的Python文件執行方式為$ python test_calculator.py,相比之下本文使用的nosetests方法功能更豐富,例如可以運行目錄中的全部測試文件。
$ nosetests test_calculator.py
E======================================================================ERROR: test_calculator_add_method_returns_correct_result (test.test_calculator.TddInPythonExample)----------------------------------------------------------------------Traceback (most recent call last):File "/Users/user/PycharmProjects/tdd_in_python/test/test_calculator.py", line 6, in test_calculator_add_method_returns_correct_resultcalc = Calculator()NameError: global name Calculator is not defined----------------------------------------------------------------------Ran 1 test in 0.001sFAILED (errors=1)
運行後可見出錯的原因是沒有導入Caculator。因為還沒有創建呢!創建的方法是在app目錄下建立calculator.py文件,然後導入:
class Calculator(object):
def add(self, x, y):pass[py] view plaincopyimport unittestfrom app.calculator import Calculatorclass TddInPythonExample(unittest.TestCase):def test_calculator_add_method_returns_correct_result(self):calc = Calculator()result = calc.add(2,2)self.assertEqual(4, result)if __name__ == __main__:unittest.main()
把Caculator構建好之後,再次運行看會出現什麼結果:
$ nosetests test_calculator.py
F======================================================================FAIL: test_calculator_add_method_returns_correct_result (test.test_calculator.TddInPythonExample)----------------------------------------------------------------------Traceback (most recent call last):File "/Users/user/PycharmProjects/tdd_in_python/test/test_calculator.py", line 9, in test_calculator_add_method_returns_correct_resultself.assertEqual(4, result)AssertionError: 4 != None----------------------------------------------------------------------Ran 1 test in 0.001sFAILED (failures=1)
很明顯,add方法返回了錯誤的值,因為還沒有為它指定行為。幸好nosetest會指出出錯的位置,方便進行修改。稍作改動後,測試便可通過了:
class Calculator(object):
def add(self, x, y):return x+y[py] view plaincopy$ nosetests test_calculator.py.----------------------------------------------------------------------Ran 1 test in 0.000sOK
雖然通過了,但是圍繞該方法還可以做更多的工作。
沉迷於某個案例很容易造成短視
如果進行非數字型數據相加會導致什麼後果呢?事實上Python是允許字元串或其它類型進行相加的,但在我們的例子裏不允許。接著嘗試就這個例子加入另一個缺陷測試,然後使用assertRaises方法來判斷是否有異常拋出:
import unittest
from app.calculator import Calculatorclass TddInPythonExample(unittest.TestCase):def setUp(self):self.calc = Calculator()def test_calculator_add_method_returns_correct_result(self):result = self.calc.add(2, 2)self.assertEqual(4, result)def test_calculator_returns_error_message_if_both_args_not_numbers(self):self.assertRaises(ValueError, self.calc.add, two, three)if __name__ == __main__:unittest.main()
以上代碼中,檢查了是否引起了ValueError錯誤,其實還可以進行更多的檢測,不過在這裡不作深入講述。此外,setup()方法用於推入計算對象。下面再看看nosetest會反饋什麼信息:
$ nosetests test_calculator.py
.F======================================================================FAIL: test_calculator_returns_error_message_if_both_args_not_numbers (test.test_calculator.TddInPythonExample)----------------------------------------------------------------------Traceback (most recent call last):File "/Users/user/PycharmProjects/tdd_in_python/test/test_calculator.py", line 15, in test_calculator_returns_error_message_if_both_args_not_numbersself.assertRaises(ValueError, self.calc.add, two, three)AssertionError: ValueError not raised----------------------------------------------------------------------Ran 2 tests in 0.001sFAILED (failures=1)
顯然nosetests告訴我們ValueError沒有被拋出。現在我們有了一個新的缺陷測試,接著嘗試編碼進行解決:
class Calculator(object):
def add(self, x, y):number_types = (int, long, float, complex)if isinstance(x, number_types) and isinstance(y, number_types):return x + yelse:raise ValueError
代碼中使用了isinstance方法是為了確保輸入的是數字型數據。
由於兩個變數的類型有多種組合,為了進行完整的測試,所以需要把可能出現的組合進行統籌並進行處理:
import unittest
from app.calculator import Calculatorclass TddInPythonExample(unittest.TestCase):def setUp(self):self.calc = Calculator()def test_calculator_add_method_returns_correct_result(self):result = self.calc.add(2, 2)self.assertEqual(4, result)def test_calculator_returns_error_message_if_both_args_not_numbers(self):self.assertRaises(ValueError, self.calc.add, two, three)def test_calculator_returns_error_message_if_x_arg_not_number(self):self.assertRaises(ValueError, self.calc.add, two, 3)def test_calculator_returns_error_message_if_y_arg_not_number(self):self.assertRaises(ValueError, self.calc.add, 2, three)if __name__ == __main__:unittest.main()
至此我們可以運行所有的測試了,所要實現的需求也都滿足了。
其它的單元測試包
py.test
pytest的作用與nosetest類似,不過可以在單獨的區域裏輸出信息,這意味著能夠使我們很快地看清楚命令行中出現的列印信息。這對於只運行單個測試的情況是很有用的。
$ nosetests test_calculator.py
....----------------------------------------------------------------------Ran 4 tests in 0.001sOK
安裝pytest的方式與nosetest差不多,命令是$ pip install pytes。執行的命令是$ pip install pytes或者指定要執行的測試文件$ py.test test/calculator_tests.py。
$ py.test test/test_calculator.py
================================================================= test session starts =================================================================platform darwin -- Python 2.7.6 -- py-1.4.26 -- pytest-2.6.4collected 4 itemstest/test_calculator.py ....============================================================== 4 passed in 0.02 seconds ===============================================================
pytest運行後的結果如下。註:只有代碼含有錯誤或異常的情況下,pytest才會進行輸出。
$ py.test test/test_calculator.py
================================================================= test session starts =================================================================platform darwin -- Python 2.7.6 -- py-1.4.26 -- pytest-2.6.4collected 4 itemstest/test_calculator.py F...====================================================================== FAILURES =======================================================================________________________________________ TddInPythonExample.test_calculator_add_method_returns_correct_result _________________________________________self = &def test_calculator_add_method_returns_correct_result(self):result = self.calc.add(3, 2)&> self.assertEqual(4, result)E AssertionError: 4 != 5test/test_calculator.py:11: AssertionError---------------------------------------------------------------- Captured stdout call -----------------------------------------------------------------X value is: 3Y value is: 2Result is 5========================================================= 1 failed, 3 passed in 0.03 seconds ==========================================================
單元測試
如果不想安裝額外的包並想保持一個純凈的標準庫結構,使用Python內建的unittest單元測試包是不錯的選擇。其使用方法如下:
if __name__ == __main__:
unittest.main()使用python calculator_tests.py執行後,看會得到什麼結果:[py] view plaincopy$ python test/test_calculator.py....----------------------------------------------------------------------Ran 4 tests in 0.004sOK
使用PDB進行調試
以TDD方式開發,經常會遇到來自代碼或測試的問題。有時這些錯誤又是比較隱蔽的。因此,需要配合使用高明的調試技術。
以TDD方式進行開發出現問題時可能難以發現
幸運地,有不少的辦法來解決這些問題。其中最簡單的方式是透過增添print語句實現「斷點」輸出。
結合print語句進行調試
加法通過後,可以嘗試進行減法調試。把app/calculator.py中的add部分代碼作如下改動:
class Calculator(object):
def add(self, x, y):number_types = (int, long, float, complex)if isinstance(x, number_types) and isinstance(y, number_types):return x - yelse:raise ValueError
這裡不妨嘗試使用print語句進行輸出,來監視值是怎樣變化的。
class Calculator(object):
def add(self, x, y):number_types = (int, long, float, complex)if isinstance(x, number_types) and isinstance(y, number_types):print X is: {}.format(x)print Y is: {}.format(y)result = x - yprint Result is: {}.format(result)return resultelse:raise ValueError
現在可以使用nosetest來執行並查看結果,可見這樣的工整輸出結構,對調試是十分有幫助的。
$ nosetests test/test_calculator.py
F...======================================================================FAIL: test_calculator_add_method_returns_correct_result (test.test_calculator.TddInPythonExample)----------------------------------------------------------------------Traceback (most recent call last):File "/Users/user/PycharmProjects/tdd_in_python/test/test_calculator.py", line 11, in test_calculator_add_method_returns_correct_resultself.assertEqual(4, result)AssertionError: 4 != 0-------------------- &>&> begin captured stdout &X is: 2Y is: 2Result is: 0--------------------- &>&> end captured stdout &----------------------------------------------------------------------Ran 4 tests in 0.002sFAILED (failures=1)
PDB進階調試
如果遇到更複雜的調試環節,僅僅依靠print語句是不夠的。其中最經常使用的進階調試工具是pdb(Python Debugger)。該工具包含在標準庫中,使用的時候只需加入一行代碼到「斷點」位置。請看下面的代碼:
class Calculator(object):
def add(self, x, y):number_types = (int, long, float, complex)if isinstance(x, number_types) and isinstance(y, number_types):import pdb; pdb.set_trace()return x - yelse:raise ValueError
請注意,如果使用nosetest執行測試,請務必使用-s標記,否則nosetest會繼續對輸出進行抓取,這樣會使pdb無法正常運行。如果是使用unittest或pytest則無需這樣做。
如果測試停止並有pdb提示,請使用list命令來進行當前代碼定位。
$ nosetests -s
&> /Users/user/PycharmProjects/tdd_in_python/app/calculator.py(7)add()-&> return x - y(Pdb) list2 def add(self, x, y):3 number_types = (int, long, float, complex)45 if isinstance(x, number_types) and isinstance(y, number_types):6 import pdb; pdb.set_trace()7 -&> return x - y8 else:9 raise ValueError[EOF](Pdb)
出現提示後是可以進行交互操作的,比方說想在這個時候檢閱x和y的值:
(Pdb) x
2(Pdb) y2
如果想了解更多命令,可以鍵入 help來查看。經常使用的命令如下所示:
- n: 步進到下個執行
- list: 顯示當前位置
- args: 顯示在當前執行點上用到的變數
- continue:運行代碼直至結束
- jump &: 運行並跳轉到行號位置
- quit/exit:停止pdb
寫在最後
TDD模式十分有趣同時能幫助提高代碼質量。不論是大型團隊還是個人開發,TDD都可運用其中。此外,成功的缺陷測試設計是非常有滿足感的。所以,不妨從今天起嘗試把TDD引入到日常工作中,親身體驗試驗前後會有什麼變化。
發佈於 2018-10-16繼續瀏覽內容怎麼做python自動化,清楚下python在那些層次能做:
不管做ui的python+selenium+unittest、python+appium+unittest;
還是做介面的python+requests
還是做平臺開發的python有flask和django
怎麼做python自動化,清楚下python在那些層次能做:
不管做ui的python+selenium+unittest、python+appium+unittest;
還是做介面的python+requests
還是做平臺開發的python有flask和django
哥,要把python運用到實際工作中去,
總學python基礎語法,用不上。
直接跟教程做一個大項目,很難,跟不上!
要一步一步來,先學會python批處理腳本, 然後寫函數,再寫類。
現在的教程都有點浮誇!
可以看看武散人的《自拍教程》,我覺得比較適合測試人員,
尤其是那種對代碼很不敏感的測試同學[驚喜],比如我
首先是需要通過學習python學會編程,學會編程再談其它的應用。
python web測試,主要用在測試自動化上。有名的selenium 就用在web 自動化測試上。Selenium - Web Browser Automation從web測試,到性能測試,單元測試,持續集成等都可以用python寫代碼來完成。先去找本python基礎書籍看看再說~
推薦閱讀: