python+selenium自動化軟件測試(第3章):unittest

3.1 unittest簡介

前言
(python基礎比較弱的,建議你們多花點時間把基礎語法學好,這裏有套視頻,能夠照着練習下:http://pan.baidu.com/s/1i44jZdb 密碼:92fs)
熟悉java的應該都清楚常見的單元測試框架Junit和TestNG,這個招聘的需求上也是常常見到的。python裏面也有單元測試框架-unittest,至關因而一個python版的junit。
python裏面的單元測試框架除了unittest,還有一個pytest框架,這個用的比較少,後面有空再繼續分享。html

3.1.1 unittest簡介

1).先導入unittestjava

2).用help函數查看源碼解析
3).查看描述:
Python unit testing framework, based on Erich Gamma's JUnit and KentBeck's Smalltalk testing framework.
翻譯:python的單元測試框架,是基於java的junit測試框架。python

3.1.2 簡單用法

1).能夠把上圖的這段代碼copy出來,單獨運行,看看測試結果。git

   Simple usage:web

import unittest
    
class IntegerArithmeticTestCase(unittest.TestCase):
       deftestAdd(self):  ## test method names begin 'test*'
            self.assertEqual((1 + 2), 3)
            self.assertEqual(0 + 1, 1)
       deftestMultiply(self):
            self.assertEqual((0 * 10), 0)
            self.assertEqual((5 * 8), 40)
    
if __name__ == '__main__':
       unittest.main()

2).第一行是導入unittest這個模塊
3).class這一行是定義一個測試的類,並繼承unittest.TestCase這個類
4).接下來是定義了兩個測試case名稱:testAdd和testMultiply
5).註釋裏面有句話很重要,這個要敲下黑板記筆記了:## test method names begin 'test*'
--翻譯:測試用例的名稱要以test開頭
6).而後是斷言assert,這裏的斷言方法是assertEqual-判斷兩個是否相等,express

這個斷言能夠是一個也能夠是多個
7).if下面的這個unittest.main()是運行主函數,運行後會看到測試結果(跑了兩個用例耗時0.000秒,兩個用例都經過):

----------------------------------------------------------------------
Ran 2 tests in 0.000s
OKpython3.x


3.1.3 小試牛刀

1).上面的兩個案例是加法和乘法,咱們能夠寫個case試下減法和除法。
2).有不少小夥伴不知道斷言怎麼寫,斷言其實就是拿實際結果和指望結果去對比,對比的方法不少,這裏只是舉的最簡單的一個判斷相等的方法。瀏覽器

3).最後運行結果,第二個是失敗的,失敗緣由:AssertionError: 3 != 3.5
F.
======================================================================
FAIL: testDivide (__main__.Test)服務器

這裏是測試除法
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:/test/web-project/p.py", line 14, in testDivide
    self.assertEqual(result, hope)
AssertionError: 3 != 3.5
----------------------------------------------------------------------
Ran 2 tests in 0.000s
FAILED (failures=1)併發

3.1.4 前置和後置

1).setUp:在寫測試用例的時候,每次操做其實都是基於打開瀏覽器輸入對應網址這些操做,這個就是執行用例的前置條件。

2).tearDown:執行完用例後,爲了避免影響下一次用例的執行,通常有個數據還原的過程,這就是執行用例的後置條件。
3).不少人執行完用例,都不去作數據還原,以至於下一個用例執行失敗,這就是不喜歡擦屁股的事情,習慣很差。
4).前置和後置都是非必要的條件,若是沒有也能夠寫pass

3.1.5 博客案例

1).打開博客首頁爲例,寫一個簡單的case
2).判斷title徹底等於指望結果
3).運行經過,下面會有一個綠條顯示:1 test passed

3.1.6 參考代碼

# coding=utf-8
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
import time
import unittest
class Blog(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.get("http://www.cnblogs.com/yoyoketang")
    def test_blog(self):
        time.sleep(3)
        result = EC.title_is(u'上海-悠悠 - 博客園')(self.driver)
        print result
        self.assertTrue(result)
    def tearDown(self):
        self.driver.quit()
if __name__ == "__main__":
    unittest.main()

3.2 unittest執行順序

前言
不少初學者在使用unittest框架時候,不清楚用例的執行順序究竟是怎樣的。對測試類裏面的類和方法分不清楚,不知道何時執行,何時不執行。
本篇經過最簡單案例詳細講解unittest執行順序。
1、案例分析
1.先定義一個測試類,裏面寫幾個簡單的case

# coding:utf-8
import unittest
import time
class Test(unittest.TestCase):
    def setUp(self):
        print "start!"
    def tearDown(self):
        time.sleep(1)
        print "end!"
    def test01(self):
        print "執行測試用例01"
    def test03(self):
        print "執行測試用例03"
    def test02(self):
        print "執行測試用例02"
    def addtest(self):
        print "add方法"
if __name__ == "__main__":
    unittest.main()

2、執行結果

D:\test\python2\python.exe D:/test/test01.py
start!
執行測試用例01
end!
start!
執行測試用例02
end!

start!

執行測試用例03

end!
.
----------------------------------------------------------------------
Ran 3 tests in 3.001s
OK

 

3、結果分析
1.執行順序:

start!-執行測試用例01-end!
start!-執行測試用例02-end!
start!-執行測試用例03-end!


2.從執行結果能夠看出幾點:
--先執行的前置setUp,而後執行的用例(test*),最後執行的後置tearDown。
--測試用例(test*)的執行順序是根據01-02-03執行的,也就是說根據用例名稱來順序執行的。
--addtest(self)這個方法沒執行,說明只執行test開頭的用例。

4、selenium實例
1.具體實例參考 登陸方法(參數化)

# coding:utf-8
from selenium import webdriver
import unittest
import time
class Bolg(unittest.TestCase):
    u'''登陸博客'''
    def setUp(self):
        self.driver = webdriver.Firefox()
        url = "https://passport.cnblogs.com/user/signin"
        self.driver.get(url)
        self.driver.implicitly_wait(30)
    def login(self, username, psw):
        u'''這裏寫了一個登陸的方法,帳號和密碼參數化'''
        self.driver.find_element_by_id("input1").send_keys(username)
        self.driver.find_element_by_id("input2").send_keys(psw)
        self.driver.find_element_by_id("signin").click()
        time.sleep(3)
    def is_login_sucess(self):
        u'''判斷是否獲取到登陸帳戶名稱'''
        try:
            text = self.driver.find_element_by_id("lnk_current_user").text
            print text
            return True
        except:
            return False
    def test_01(self):
        u'''登陸案例參考:帳號,密碼本身設置'''
        self.login(u"上海-悠悠", u"xxxx"# 調用登陸方法
        # 判斷結果
        result = self.is_login_sucess()
        self.assertTrue(result)
    def test_02(self):
        u'''登陸案例參考:帳號,密碼本身設置'''
        self.login(u"上海-悠悠", u"xxxx"# 調用登陸方法
        # 判斷結果
        result = self.is_login_sucess()
        self.assertTrue(result)
    def tearDown(self):
        self.driver.quit()

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

3.3 unittest批量執行

咱們在寫用例的時候,單個腳本的用例好執行,那麼多個腳本的時候,如何批量執行呢?這時候就須要用到unittet裏面的discover方法來加載用例了。
加載用例後,用unittest裏面的TextTestRunner這裏類的run方法去一次執行多個腳本的用例。
1、新建測試項目
1.pycharm左上角File>New Projetc>Pure Python,在location位置命名一個測試工程的名稱:yoyotest,而後保存

 

 2.選中剛纔新建的工程右鍵>New>Python Package>新建一個case文件夾

3.重複第2步的操做,新建一個case的文件夾,在裏面添加一個baidu和一個blog的文件夾,裏面分別有兩個用例的腳本,以下圖所示。
test_01,test_02,test_03,test_04是咱們寫用例的腳本
4.test_01建立完後,打開腳本,寫入用例

5.在yoyotest這個項目下面建立一個腳本run_all_case.py,接下來用這個腳本去批量執行全部的用例。

2、diascover加載測試用例
1.discover方法裏面有三個參數:

-case_dir:這個是待執行用例的目錄。
-pattern:這個是匹配腳本名稱的規則,test*.py意思是匹配test開頭的全部腳本。
-top_level_dir:這個是頂層目錄的名稱,通常默認等於None就好了。

2.discover加載到的用例是一個list集合,須要從新寫入到一個list對象testcase裏,這樣就能夠用unittest裏面的TextTestRunner這裏類的run方法去執行。

3.運行後結果以下,就是加載到的全部測試用例了:

<unittest.suite.TestSuite tests=[<baidu.test_01.Test testMethod=test01>, <baidu.test_01.Test testMethod=test02>, <baidu.test_01.Test testMethod=test03>, <baidu.test_02.Test
testMethod=test01>, <baidu.test_02.Test testMethod=test02>, <baidu.test_02.Test testMethod=test03>, <bolg.test_03.Test testMethod=test01>, <bolg.test_03.Test testMethod=test02>,
<bolg.test_03.Test testMethod=test03>, <bolg.test_04.Test testMethod=test01>, <bolg.test_04.Test testMethod=test02>, <bolg.test_04.Test testMethod=test03>]>

3、run測試用例
1.爲了更方便的理解,能夠把上面discover加載用例的方法封裝下,寫成一個函數

2.參考代碼:

# coding:utf-8
import unittest
import os
# 用例路徑
case_path = os.path.join(os.getcwd(), "case")
# 報告存放路徑
report_path = os.path.join(os.getcwd(), "report")
def all_case():
    discover = unittest.defaultTestLoader.discover(case_path, pattern="test*.py", top_level_dir=None)
    print(discover)
    return discover
if __name__ == "__main__":
    runner = unittest.TextTestRunner()
    runner.run(all_case())

3.4 unittest之裝飾器(@classmethod)

前言
前面講到unittest裏面setUp能夠在每次執行用例前執行,這樣有效的減小了代碼量,可是有個弊端,好比打開瀏覽器操做,每次執行用例時候都會從新打開,這樣就會浪費不少時間。
因而就想是否是能夠只打開一次瀏覽器,執行完用例再關閉呢?這就須要用到裝飾器(@classmethod)來解決了。
 
1、裝飾器
1.用setUp與setUpClass區別

setup():每一個測試case運行前運行
teardown():每一個測試case運行完後執行
setUpClass():必須使用@classmethod 裝飾器,全部case運行前只運行一次
tearDownClass():必須使用@classmethod裝飾器,全部case運行完後只運行一次

2.@是修飾符,classmethod是python裏的類方法

 

2、執行順序
1.用類方法寫幾個簡單case,能夠對比這篇:Selenium2+python自動化52-unittest執行順序

# coding:utf-8
import unittest
import time
class Test(unittest.TestCase):     @classmethod     def setUpClass(cls):         print "start!"         @classmethod     def tearDownClass(cls):         time.sleep(1)         print "end!"     def test01(self):         print "執行測試用例01"     def test03(self):         print "執行測試用例03"     def test02(self):         print "執行測試用例02"     def addtest(self):         print "add方法"

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

2.從執行結果能夠看出,前置和後置在執行用例前只執行了一次。
start!
執行測試用例01
執行測試用例02
執行測試用例03
...end!

----------------------------------------------------------------------
Ran 3 tests in 1.001s

3、selenium實例
1.能夠把打開瀏覽器操做放到前置setUpClass(cls)裏,這樣就能夠實現打開一次瀏覽器,執行多個case了

# coding:utf-8
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
import unittest
class BolgHome(unittest.TestCase):
    u
'''博客首頁'''     @classmethod     def setUpClass(cls):         cls.driver = webdriver.Firefox()         url = "http://www.cnblogs.com/yoyoketang/"         cls.driver.get(url)         cls.driver.implicitly_wait(30)
    @classmethod    
def tearDownClass(cls):         cls.driver.quit()
   
def test_01(self):         u'''驗證元素存在:博客園'''         locator = ("id", "blog_nav_sitehome")         text = u"博客園"         result = EC.text_to_be_present_in_element(locator, text)(self.driver)         self.assertTrue(result)     def test_02(self):         u'''驗證元素存在:首頁'''         locator = ("id", "blog_nav_myhome")         text = u"首頁"         result = EC.text_to_be_present_in_element(locator, text)(self.driver)         self.assertTrue(result)
if __name__ == "__main__":     unittest.main()

       上述代碼運行的順序就是從上至下,而再也不是每次執行完成一個testcase以後,執行一次teardownClass再進行下一個testcase。

  這樣一來,退出瀏覽器僅僅執行一次便可,這樣有一個很差的地方就是,teardownClass這個函數不能再進行每一個測試用例的終結操做,好比:修改我的信息後恢復到登陸成功後的狀態,對當前測試用例的異常處理等。

  後來,本人嘗試在tearDownClass後增長以下代碼:

def tearDown(self):
    self.driver.refresh()
    self.assertEqual( [], self.verificationErrors )

     而後,果真每次測試用完成都會刷新當前頁面,這樣一來,每個testcase的用例都能被終結函數tearDown結束,最後再執行tearDownClass關閉測試瀏覽器。

     須要說明的是:

  @classmethod是python自己的裝飾器,因此他不要使用隸屬於unittest框架下斷言assertEqual。

  unittest自己也帶有裝飾器unittest.skip(),專門用於跳過testcase的裝飾器,其用法以下:

     

 @unittest.skip(reason), skip裝飾器:直接跳過裝飾下的testcase,reason用來講明緣由,下同。

 @unittest.skipIf(condition,reason), skipIf裝飾器:condition條件爲True時,跳過裝飾下的testcase,計入skip的testcase執行次數。

 @unittest.skipUnless(condition,reason),skipUnless裝飾器:condition條件爲False時,跳過裝飾下的testcase,計入skip的testcase執行次數。

 @unittest.expectedFailure(), expectedFailure裝飾器:執行裝飾下的testcase,執行失敗則跳過該testcase,計入expected下成敗的testcase次數。

  通常來說,使用@unittest.skipIf 或者 @unittest.skipUnless,應該也能實現@classmethod裝飾器的效果, 想來只是實現起來相對來講較爲麻煩。

3.5 unittest生成測試報告HTMLTestRunner

前言
批量執行完用例後,生成的測試報告是文本形式的,不夠直觀,爲了更好的展現測試報告,最好是生成HTML格式的。
unittest裏面是不能生成html格式報告的,須要導入一個第三方的模塊:HTMLTestRunner
備註:(如下是python2.7的HTMLTestRunner,python3.x的HTMLTestRunner須要本身稍作修改,能夠在這裏下載:http://pan.baidu.com/s/1hs5OXNY)
 
1、導入HTMLTestRunner
1.這個模塊下載不能經過pip安裝了,只能下載後手動導入,下載地址:http://tungwaiyip.info/software/HTMLTestRunner.html

2.Download下HTMLTestRunner.py文件就是咱們須要下載的包。
3.下載後手動拖到python安裝文件的Lib目錄下

2、demo解析

1.下載Download下的第二個文件test_HTMLTestRunner.py,這個就是官方給的一個測試demo了,從這個文件能夠找到該模塊的用法。
2.找到下圖這段,就是官方給的一個demo了,test_main()裏上半部分就是加載測試case,咱們不須要搞這麼複雜。
參考前面一篇內容就好了Selenium2+python自動化53-unittest批量執行(discover)
3.最核心的代碼是下面的紅色區域,這個就是本篇的重點啦。

3、生成html報告
1.咱們只需把上面紅色區域代碼copy到上一篇的基礎上稍作修改就能夠了,這裏主要有三個參數:
--stream:測試報告寫入文件的存儲區域
--title:測試報告的主題
--description:測試報告的描述
2.report_path是存放測試報告的地址

4、測試報告詳情
1.找到測試報告文件,用瀏覽器打開,點開View裏的Detail能夠查看詳情描述。

2.爲了生成帶中文描述的測試用例,能夠在case中添加註釋,如在test_01的腳本添加以下注釋:

class Test(unittest.TestCase):
    def setUp(self):
        print "start!"
    def tearDown(self):
        time.sleep(1)
        print "end!"
    def test01(self):
        u'''測試登陸用例,帳號:xx 密碼xx'''
        print "執行測試用例01"
    def test03(self):
        u'''測試登搜索用例,關鍵詞:xxx'''
        print "執行測試用例03"

 

3.從新運行後查看測試報告

 

5、參考代碼:
1.我下面的代碼文件路徑用的相對路徑,這樣就避免代碼換個地址找不到路徑的狀況了

# coding:utf-8
import unittest
import os
import HTMLTestRunner
# 用例路徑
case_path = os.path.join(os.getcwd(), "case")
# 報告存放路徑
report_path = os.path.join(os.getcwd(), "report")
def all_case():
    discover = unittest.defaultTestLoader.discover(case_path, pattern="test*.py", top_level_dir=None)
    print(discover)
    return discover

if __name__ == "__main__":
    # runner = unittest.TextTestRunner()
    # runner.run(all_case())
    # html報告文件路徑
    report_abspath = os.path.join(report_path, "result.html")
    fp = open(report_abspath, "wb")
    runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title=u'自動化測試報告,測試結果以下:', description=u'用例執行狀況:')
    # 調用add_case函數返回值
    runner.run(all_case())
    fp.close()

3.6 html報告亂碼問題優化

前言
python2用HTMLTestRunner生成測試報告時,有中文輸出狀況會出現亂碼,這個主要是編碼格式不統一,改下編碼格式就行。
下載地址:http://tungwaiyip.info/software/HTMLTestRunner.html
 
1、中文亂碼
1.測試報告中,msg自定義異常內容有中文狀況會出現亂碼,以下圖所示

 

2、修改編碼
1.找到HTMLTestRunner.py文件,搜索:uo =
2.找到紅色區域設置編碼的兩個地方

3.註釋掉紅色區域這兩個設置,從新添加編碼格式爲:uo = o.decode('utf-8')   ue = e.decode('utf-8')

4.修改好以後記得保存,從新運行,亂碼問題就解決了

3、python3報告問題
1.python3的小夥伴直接用這個下載地址:http://tungwaiyip.info/software/HTMLTestRunner.html的文件,是不能直接生成報告的,須要稍作修改
2.修改後的源文件已經打包:https://files.cnblogs.com/files/zidonghua/HTMLTestRunner%28%E7%8B%AC%E5%AE%B6%E5%90%88%E9%9B%86%29.zip

(另外不少朋友在簡單的示例代碼中,生成不了測試報告,我來上傳一份完整項目模板:https://files.cnblogs.com/files/zidonghua/%E6%B5%8B%E8%AF%95%E6%8A%A5%E5%91%8A%E6%90%9E%E4%B8%8D%E5%87%BA%E6%9D%A5%E7%9A%84%E7%9C%8B%E8%BF%99%E9%87%8C.rar

3.7 unittest之斷言

前言
在測試用例中,執行完測試用例後,最後一步是判斷測試結果是pass仍是fail,自動化測試腳本里面通常把這種生成測試結果的方法稱爲斷言(assert)。
用unittest組件測試用例的時候,斷言的方法仍是不少的,下面介紹幾種經常使用的斷言方法:assertEqual、assertIn、assertTrue

3.7.1 簡單案例


1).下面寫了4個case,其中第四個是執行失敗的

# coding:utf-8
import unittest

class Test(unittest.TestCase):
    def test01(self):
        '''判斷 a == b '''
        a = 1
        b = 1
        self.assertEqual(a, b)
    def test02(self):
        '''判斷 a in b'''
        a = "hello"
        b = "hello world!"
        self.assertIn(a, b)

    def test03(self):
        '''判斷 a isTrue '''
        a = True
        self.assertTrue(a)
    def test04(self):
        '''失敗案例'''
        a = "上海-悠悠"
        b = "yoyo"
        self.assertEqual(a, b)

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

2).執行結果以下
Failure
Expected :'\xe4\xb8\x8a\xe6\xb5\xb7-\xe6\x82\xa0\xe6\x82\xa0'
Actual   :'yoyo'
 <Click to see difference>
Traceback (most recent call last):
  File "D:\test\yoyotest\kecheng\test12.py", line 27, in test04
    self.assertEqual(a, b)
AssertionError: '\xe4\xb8\x8a\xe6\xb5\xb7-\xe6\x82\xa0\xe6\x82\xa0' != 'yoyo'
3.執行的結果,中文編碼不對,沒正常顯示中文,遇到這種狀況,能夠自定義異常輸出

3.7.2 自定義異常

1).以assertEqual爲例分析:
assertEqual(self, first, second, msg=None)
    Fail if the two objects are unequal as determined by the'=='
    operator.
2).翻譯:若是兩個對象不能相等,就返回失敗,至關於return: first==second
3).這裏除了相比較的兩個參數first和second,還有第三個參數msg=None,這個msg參數就是遇到異常後自定義輸出信息

3.7.3 unittest經常使用的斷言方法

1).assertEqual(self, first, second,msg=None)

--判斷兩個參數相等:first == second
2).assertNotEqual(self, first, second,msg=None)
--判斷兩個參數不相等:first != second
3).assertIn(self, member, container,msg=None)
--判斷是字符串是否包含:member in container
4).assertNotIn(self, member,container, msg=None)
--判斷是字符串是否不包含:member not in container
5).assertTrue(self, expr, msg=None)
--判斷是否爲真:expr is True
6).assertFalse(self, expr, msg=None)
--判斷是否爲假:expr is False

7).assertIsNone(self, obj, msg=None)
--判斷是否爲None:objis None
8).assertIsNotNone(self, obj,msg=None)
--判斷是否不爲None:obj is not None
3.7.4 unittest全部斷言方法
1).下面是unittest框架支持的全部斷言方法,有興趣的同窗能夠慢慢看。(官方資料)

|  assertAlmostEqual(self, first, second, places=None, msg=None,delta=None)
|      Fail if the two objects are unequal asdetermined by their
|      difference rounded to the given number ofdecimal places
|      (default 7) and comparing to zero, or bycomparing that the
|      between the two objects is more than the givendelta.
|      
|      Note that decimal places (from zero) areusually not the same
|      as significant digits (measured from the mostsignficant digit).
|      
|      If the two objects compare equal then they willautomatically
|      compare almost equal.
|  
|  assertAlmostEquals = assertAlmostEqual(self, first, second,places=None, msg=None, delta=None)
|  
|  assertDictContainsSubset(self, expected, actual, msg=None)
|      Checks whether actual is a superset ofexpected.
|  
|  assertDictEqual(self, d1, d2, msg=None)
|  
|  assertEqual(self, first, second, msg=None)
|      Fail if the two objects are unequal asdetermined by the '=='
|      operator.
|  
|  assertEquals = assertEqual(self, first, second, msg=None)
| 
|  assertFalse(self, expr, msg=None)
|      Check that the expression is false.
|  
|  assertGreater(self, a, b, msg=None)
|      Just like self.assertTrue(a > b), but with anicer default message.
|  
|  assertGreaterEqual(self, a, b, msg=None)
|      Just like self.assertTrue(a >= b), but witha nicer default message.
|  
|  assertIn(self, member, container, msg=None)
|      Just like self.assertTrue(a in b), but with anicer default message.
|  
|  assertIs(self, expr1, expr2, msg=None)
|      Just like self.assertTrue(a is b), but with anicer default message.
|  
|  assertIsInstance(self, obj, cls, msg=None)
|      Same as self.assertTrue(isinstance(obj, cls)),with a nicer
|      default message.
|  
|  assertIsNone(self, obj, msg=None)
|      Same as self.assertTrue(obj is None), with anicer default message.
|  
|  assertIsNot(self, expr1, expr2, msg=None)
|      Just like self.assertTrue(a is not b), but witha nicer default message.
|  
|  assertIsNotNone(self, obj, msg=None)
|      Included for symmetry with assertIsNone.
|  
|  assertItemsEqual(self, expected_seq, actual_seq, msg=None)
|      An unordered sequence specific comparison. Itasserts that
|      actual_seq and expected_seq have the sameelement counts.
|      Equivalent to::
|      
|         self.assertEqual(Counter(iter(actual_seq)),
|                          Counter(iter(expected_seq)))
|      
|      Asserts that each element has the same count inboth sequences.
|      Example:
|          - [0, 1, 1] and [1, 0,1] compare equal.
|          - [0, 0, 1] and [0, 1]compare unequal.
|  
|  assertLess(self, a, b, msg=None)
|      Just like self.assertTrue(a < b), but with anicer default message.
|  
|  assertLessEqual(self, a, b, msg=None)
|      Just like self.assertTrue(a <= b), but witha nicer default message.
|  
|  assertListEqual(self, list1, list2, msg=None)
|      A list-specific equality assertion.
|      
|      Args:
|          list1: The first listto compare.
|          list2: The second listto compare.
|          msg: Optional messageto use on failure instead of a list of
|                 differences.
|  
|  assertMultiLineEqual(self, first, second, msg=None)
|      Assert that two multi-line strings are equal.
|  
|  assertNotAlmostEqual(self, first, second, places=None, msg=None,delta=None)
|      Fail if the two objects are equal as determinedby their
|      difference rounded to the given number ofdecimal places
|      (default 7) and comparing to zero, or bycomparing that the
|      between the two objects is less than the givendelta.
|      
|      Note that decimal places (from zero) areusually not the same
|      as significant digits (measured from the mostsignficant digit).
|      
|      Objects that are equal automatically fail.
|  
|  assertNotAlmostEquals = assertNotAlmostEqual(self, first, second, places=None,msg=None, delta=None)
|  
|  assertNotEqual(self, first, second, msg=None)
|      Fail if the two objects are equal as determinedby the '!='
|      operator.
|  
|  assertNotEquals = assertNotEqual(self, first, second, msg=None)
|  
|  assertNotIn(self, member, container, msg=None)
|      Just like self.assertTrue(a not in b), but witha nicer default message.
|  
|  assertNotIsInstance(self, obj, cls, msg=None)
|      Included for symmetry with assertIsInstance.
|  
|  assertNotRegexpMatches(self, text, unexpected_regexp, msg=None)
|      Fail the test if the text matches the regularexpression.
|  
|  assertRaises(self, excClass, callableObj=None, *args, **kwargs)
|      Fail unless an exception of class excClass israised
|      by callableObj when invoked with arguments argsand keyword
|      arguments kwargs. If a different type ofexception is
|      raised, it will not be caught, and the testcase will be
|      deemed to have suffered an error, exactly asfor an
|      unexpected exception.
|      
|      If called with callableObj omitted or None,will return a
|      context object used like this::
|      
|           withself.assertRaises(SomeException):
|              do_something()
|      
|      The context manager keeps a reference to theexception as
|      the 'exception' attribute. This allows you toinspect the
|      exception after the assertion::
|      
|          withself.assertRaises(SomeException) as cm:
|             do_something()
|          the_exception =cm.exception
|         self.assertEqual(the_exception.error_code, 3)
|  
|  assertRaisesRegexp(self, expected_exception, expected_regexp,callable_obj=None, *args, **kwargs)
|      Asserts that the message in a raised exceptionmatches a regexp.
|      
|      Args:
|          expected_exception:Exception class expected to be raised.
|          expected_regexp: Regexp(re pattern object or string) expected
|                 to be found in error message.
|          callable_obj: Functionto be called.
|          args: Extra args.
|          kwargs: Extra kwargs.
|  
|  assertRegexpMatches(self, text, expected_regexp, msg=None)
|      Fail the test unless the text matches theregular expression.
|  
|  assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None)
|      An equality assertion for ordered sequences(like lists and tuples).
|      
|      For the purposes of this function, a validordered sequence type is one
one
|      which can be indexed, has a length, and has anequality operator.
|      
|      Args:
|          seq1: The firstsequence to compare.
|          seq2: The secondsequence to compare.
|          seq_type: The expecteddatatype of the sequences, or None if no
|                 datatype should be enforced.
|          msg: Optional messageto use on failure instead of a list of
|                 differences.
|  
|  assertSetEqual(self, set1, set2, msg=None)
|      A set-specific equality assertion.
|      
|      Args:
|          set1: The first set tocompare.
|          set2: The second set tocompare.
|          msg: Optional messageto use on failure instead of a list of
|                 differences.
|      
|      assertSetEqual uses ducktyping to supportdifferent types of sets, and
|      is optimized for sets specifically (parametersmust support a
|      difference method).
|  
|  assertTrue(self, expr, msg=None)
|      Check that the expression is true.
|  
|  assertTupleEqual(self, tuple1, tuple2, msg=None)
|      A tuple-specific equality assertion.
|      
|      Args:
|          tuple1: The first tupleto compare.
|          tuple2: The secondtuple to compare.
|          msg: Optional messageto use on failure instead of a list of
|                 differences.

3.8 搭建簡易項目

前言
到unittest這裏基本上能夠搭建一個簡易的項目框架了,咱們能夠用一條run_main.py腳本去控制執行全部的用例,並生成報告,發送郵件一系列的動做
 
1、新建工程
1.打開pycharm左上角File>New Project,在Location位置輸入項目名稱:D:\test\test_blog
2.建立以後,選擇Opin in current window就能夠了

2、項目結構
1.在測試工程下,建立文件夾,必定要選Python Package的方式建立,要否則後面導入本身寫的模塊會出現各類問題

2.在工程下建立如下幾個文件
--test_case           這個文件夾放全部測試用例
----blog_home       能夠按功能用例模塊劃分
---------test_home

---------test_home_1     測試用例以test開頭命名
----blog_login
---------test_login
----blog_set
---------test_set
--test_report
--run_main.py          注意這個腳本放文件根目錄

3、run_main
1.run_main.py這個腳本里面寫主函數,控制執行全部的用例,最終咱們只須要運行這個腳本就能夠了

2.咱們也能夠在cmd裏執行這個腳本文件,這樣就不用依賴pycharm去執行了(後續用jenkins執行,也是一樣道理,啓動cmd執行腳本)
>>d:
>>cd test\test_blog
>>python run_main.py

 

 3.run_main.py源代碼在下一章節。

3.8-1 生成報告的源碼下載(兼容python2和3)

生成測試項目報告模板:

https://files.cnblogs.com/files/zidonghua/%E7%94%9F%E6%88%90%E6%B5%8B%E8%AF%95%E6%8A%A5%E5%91%8A%E9%A1%B9%E7%9B%AE%E6%A8%A1%E6%9D%BF.zip

測試報告搞不出來的看這裏:

https://files.cnblogs.com/files/zidonghua/%E6%B5%8B%E8%AF%95%E6%8A%A5%E5%91%8A%E6%90%9E%E4%B8%8D%E5%87%BA%E6%9D%A5%E7%9A%84%E7%9C%8B%E8%BF%99%E9%87%8C2.rar

 

3.9 run_main.py源碼(兼容python2和3)

如下代碼在python2和python3上都跑經過,python3只需註釋掉上面紅色框框區域代碼就行(最後一步發送郵箱代碼,我註釋掉了)。

# coding=utf-8
import unittest
import time
import HTMLTestRunner
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import smtplib
import os
####下面三行代碼python2報告出現亂碼時候能夠加上####
import sys
reload(sys)
sys.setdefaultencoding('utf8')

# 這個是優化版執行全部用例併發送報告,分四個步驟 # 第一步加載用例 # 第二步執行用例 # 第三步獲取最新測試報告 # 第四步發送郵箱 (這一步不想執行的話,能夠註釋掉最後面那個函數就行)
def add_case(case_path, rule):     '''加載全部的測試用例'''     testunit = unittest.TestSuite()     # 定義discover方法的參數     discover = unittest.defaultTestLoader.discover(case_path,                                                   pattern=rule,                                                   top_level_dir=None)     # discover方法篩選出來的用例,循環添加到測試套件中     # for test_suite in discover:     #     for test_case in test_suite:     #         testunit.addTests(test_case)     #         print testunit     testunit.addTests(discover)  # 直接加載discover     print(testunit)     return testunit
def run_case(all_case, report_path):     '''執行全部的用例, 並把結果寫入測試報告'''     now = time.strftime("%Y_%m_%d %H_%M_%S")     report_abspath = os.path.join(report_path, now+"result.html")     # report_abspath = "D:\\web_project\\report\\"+now+"result.html"     fp = open(report_abspath, "wb")     runner = HTMLTestRunner.HTMLTestRunner(stream=fp,                                            title=u'自動化測試報告,測試結果以下:',                                            description=u'用例執行狀況:')     # 調用add_case函數返回值     runner.run(all_case)     fp.close()
def get_report_file(report_path):     '''獲取最新的測試報告'''     lists = os.listdir(report_path)     lists.sort(key=lambda fn: os.path.getmtime(os.path.join(report_path, fn)))     print (u'最新測試生成的報告: '+lists[-1])     # 找到最新生成的報告文件     report_file = os.path.join(report_path, lists[-1])     return report_file
def send_mail(sender, psw, receiver, smtpserver, report_file):     '''發送最新的測試報告內容'''     # 讀取測試報告的內容     with open(report_file, "rb") as f:         mail_body = f.read()     # 定義郵件內容     msg = MIMEMultipart()     body = MIMEText(mail_body, _subtype='html', _charset='utf-8')     msg['Subject'] = u"自動化測試報告"     msg["from"] = sender     msg["to"] = psw     # 加上時間戳     # msg["date"] = time.strftime('%a, %d %b %Y %H_%M_%S %z')     msg.attach(body)     # 添加附件     att = MIMEText(open(report_file, "rb").read(), "base64", "utf-8")     att["Content-Type"] = "application/octet-stream"     att["Content-Disposition"] = 'attachment; filename= "report.html"'     msg.attach(att)     # 登陸郵箱     smtp = smtplib.SMTP()     # 鏈接郵箱服務器     smtp.connect(smtpserver)     # 用戶名密碼     smtp.login(sender, psw)     smtp.sendmail(sender, receiver, msg.as_string())     smtp.quit()     print('test report email has send out !')
if __name__ == "__main__":     # 測試用例的路徑、匹配規則     case_path = "D:\\test\\newp\\case"     rule = "test*.py"     all_case = add_case(case_path, rule)   # 1加載用例     # 生成測試報告的路徑     report_path = "D:\\test\\newp\\report"     run_case(all_case, report_path)        # 2執行用例     # 獲取最新的測試報告文件     report_file = get_report_file(report_path)  # 3獲取最新的測試報告     #郵箱配置     sender = "yoyo@xxx.com"     psw = "xxx"     # 收件人多個時,中間用逗號隔開,如'a@xx.com,b@xx.com'     receiver = "yoyo@xxx.com"     smtp_server = 'smtp.xxx.com'     # send_mail(sender, psw, receiver, smtp_server, report_file)  # 4最後一步發送報告,須要發郵件就取消註釋。

3.10 練習題1:模塊導入(登陸方法)

以登陸博客園爲案例https://passport.cnblogs.com/user/signin
1、登陸方法封裝
1.咱們能夠把登陸寫成一個登陸類,裏面寫個登陸的方法,保存文件爲login_pub.py

# coding:utf-8
'''
這裏寫了一個登陸博客園的類,登陸博客園方法
'''
class Login_Blog():
   '''登陸類封裝'''

   def __init__(self, driver):
       '''初始化driver參數'''
       self.driver = driver
   
   def input_user(self, username):
       '''輸入用戶名'''
       self.driver.find_element_by_id("input1").clear()
       self.driver.find_element_by_id("input1").send_keys(username)
   
   def input_psw(self,psw):
       '''輸入密碼'''
       self.driver.find_element_by_id("input2").clear()
       self.driver.find_element_by_id("input2").send_keys(psw)
       
   def click_button(self):
       '''點擊登陸按鈕'''
       self.driver.find_element_by_id("signin").click()
       
   def login(self, username, psw):
       '''登陸公共方法'''
       self.input_user(username)
       self.input_psw(psw)
       self.click_button()

2.調用登陸公共方法

# coding:utf-8
from selenium import webdriver
import unittest
from login_pub import Login_Blog
login_url = "https://passport.cnblogs.com/user/signin"
class TetsLogin(unittest.TestCase):    def setUp(self):        self.driver = webdriver.Firefox()        self.driver.get(login_url)    def tearDown(self):        self.driver.quit()    def test_login(self):        # 調用登陸類裏面的login方法        Login_Blog(self.driver).login("xxx", "111")        self.driver.find_element()  # 後面接着的操做省略了

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

3.11 練習題2:捕獲異常

前言
在定位元素的時候,常常會遇到各類異常,爲何會發生這些異常,遇到異常又該如何處理呢?
本篇經過學習selenium的exceptions模塊,瞭解異常發生的緣由。
1、發生異常
1.打開博客首頁,定位「新隨筆」元素,此元素id="blog_nav_newpost"
2.爲了故意讓它定位失敗,我在元素屬性後面加上xx
3.運行失敗後以下圖所示,程序在查找元素的這一行發生了中斷,不會繼續執行click事件了

2、捕獲異常
1.爲了讓程序繼續執行,咱們能夠用try...except...捕獲異常。捕獲異常後能夠打印出異常緣由,這樣以便於分析異常緣由。

2.從以下異常內容能夠看出,發生異常緣由是:NoSuchElementException
selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: {"method":"id","selector":"blog_nav_newpostxx"}

3.從selenium.common.exceptions 導入 NoSuchElementException類。

3、參考代碼:

# coding:utf-8
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
driver
= webdriver.Firefox() driver.get("http://www.cnblogs.com/yoyoketang/")
# 定位首頁"新隨筆" try: element = driver.find_element("id", "blog_nav_newpostxx") except NoSuchElementException as msg: print u"查找元素異常%s"%msg # 點擊該元素 else: element.click()

 

4、selenium常見異常
1.NoSuchElementException:沒有找到元素
2.NoSuchFrameException:沒有找到iframe
3.NoSuchWindowException:沒找到窗口句柄handle
4.NoSuchAttributeException:屬性錯誤
5.NoAlertPresentException:沒找到alert彈出框
6.ElmentNotVisibleException:元素不可見
7.ElementNotSelectableException:元素沒有被選中
8.TimeoutException:查找元素超時

備註:其它異常與源碼在Lib目錄下:selenium/common/exceptions有興趣的能夠看看。

3.12 練習題3:異常後截圖

前言
在執行用例過程當中因爲是無人值守的,用例運行報錯的時候,咱們但願能對當前屏幕截圖,留下證據。
在寫用例的時候,最後一步是斷言,能夠把截圖的動做放在斷言這裏,那麼如何在斷言失敗後截圖呢?
 
1、截圖方法
1.get_screenshot_as_file(self, filename)
--這個方法是獲取當前window的截圖,出現IOError時候返回False,截圖成功返回True。
filename參數是保存文件的路徑。

   Usage:
       driver.get_screenshot_as_file('/Screenshots/foo.png')
 
2.get_screenshot_as_base64(self)
--這個方法也是獲取屏幕截圖,保存的是base64的編碼格式,在HTML界面輸出截圖的時候,會用到。
好比,想把截圖放到html測試報告裏。
   Usage:
       driver.get_screenshot_as_base64()
 
3.get_screenshot_as_png(self)
   --這個是獲取屏幕截圖,保存的是二進制數據,不多用到。

    Usage:
       driver.get_screenshot_as_png()

2、異常後截圖
1.爲了能拋異常,把定位登陸按鈕的id換了個錯的id。
2.給圖片命名時候加個時間戳,避免同一個文件名稱被覆蓋掉。
3.文件路徑,這裏直接寫的文件名稱,就是跟當前的腳本同一個路徑。若是圖片輸出到其它文件路徑,須要些文件的絕對路徑了。
4.截圖的結果,若是沒截到圖返回False,截圖成功會返回True。

 

 

3、selenium實例
1.在unittest框架裏寫用例的時候,咱們但願在斷言失敗的時候,對當前屏幕截圖。
2.若是加try...except捕獲異常後結果,此時全部的測試用例都是經過的了,會影響測試結果。解決辦法其實很簡單,再把異常拋出來就好了。

3.參考代碼:

# coding:utf-8
from selenium import webdriver
import time,unittest
from selenium.webdriver.support import expected_conditions as EC
class Login(unittest.TestCase):     def setUp(self):         url_login = "https://passport.cnblogs.com/user/signin"         self.driver = webdriver.Firefox()         self.driver.get(url_login)     def test_01(self):         '''前面輸入帳號密碼,讓正確運行到assert這一步,斷言故意設置爲Fals e不成功'''         try:             self.driver.find_element_by_id("input1").send_keys(u"上海-悠悠")             self.driver.find_element_by_id("input2").send_keys("xxx")             # 登陸id是錯的,定位會拋異常             self.driver.find_element_by_id("signin").click()             # 判斷登陸成功頁面是否有帳號:"上海-悠悠"             time.sleep(3)             locator = ("id", "lnk_current_user")             result = EC.text_to_be_present_in_element(locator,u"上海-悠悠")(self.driver)             self.assertFalse(result)         except Exception as msg:             print(u"異常緣由%s"%msg)             # 圖片名稱能夠加個時間戳             nowTime = time.strftime("%Y%m%d.%H.%M.%S")             self.driver.get_screenshot_as_file('%s.jpg' % nowTime)             raise     def tearDown(self):         self.driver.quit()
if __name__ == "__main__":     unittest.main()

4.運行結果:
異常緣由True is not false

Failure
Traceback (most recent call last):
  File "D:\test\yoyot\ketang\test01.py", line 22, in test_01
    self.assertFalse(result)
AssertionError: True is not false

3.13 練習題4:郵件發送(smtp)

前言
本篇總結了QQ郵箱和163郵箱發送郵件,郵件包含html中文和附件,能夠發給多個收件人,專治各類不行,總之看完這篇麻麻不再用擔憂個人郵件收不到了。
如下代碼兼容python2和python3,運行無異常,放心大膽食用。
 
1、163郵箱
1.先導入smtplib庫用來發送郵件,導入MIMEText庫用來作純文本的郵件模板
2.先準備幾個跟發郵件相關的參數,每一個郵箱的發件服務器都不同,以163爲例,百度搜到發件服務器爲:smtp.163.com

3.接下來就是寫郵件的主題和正文內容,正文這裏用html格式的
4.最後調用SMTP發件服務

5.參考代碼:

# coding:utf-8
import smtplib
from email.mime.text import MIMEText
# ----------1.跟發件相關的參數------ smtpserver = "smtp.163.com"            # 發件服務器 port = 0                                            # 端口 sender = "yoyo@163.com"                # 帳號 psw = "**************"                         # 密碼 receiver = "283340479@qq.com"        # 接收人

# ----------2.編輯郵件的內容------ subject = "這個是主題163" body = '<p>這個是發送的163郵件</p>'  # 定義郵件正文爲html格式 msg = MIMEText(body, "html", "utf-8") msg['from'] = sender msg['to'] = "283340479@qq.com" msg['subject'] = subject
# ----------3.發送郵件------ smtp = smtplib.SMTP() smtp.connect(smtpserver)                                  # 連服務器 smtp.login(sender, psw)                                     # 登陸 smtp.sendmail(sender, receiver, msg.as_string())  # 發送 smtp.quit()                                                         # 關閉

2、QQ郵件

1.QQ郵箱是須要SSL認證的,這種郵箱跟上面的就有點不同了。

2.找到QQ郵箱受權碼,打開QQ郵箱-設置-帳號-POP3開啓服務-開啓
(若是已經開啓了,不知道受權碼,就點舒適提示裏面的‘生成受權碼’)

 

 3.發驗證短信獲取受權碼,照着提示發個短信,如何點我已發送,就會收到受權碼了。

4.收到受權碼後複製,保存下來,這個就能夠當QQ郵箱的密碼了。

 

 

 5.QQ郵箱發送郵件代碼,跟163有點不同,以下圖紅色框框:

6.參考代碼:

# coding:utf-8
import smtplib
from email.mime.text import MIMEText
# ----------1.跟發件相關的參數------ # smtpserver = "smtp.163.com"         # 發件服務器 smtpserver = "smtp.qq.com" port = 465                                        # 端口 sender = "283340479@qq.com"         # 帳號 psw = "**************"                         # 密碼 receiver = "283340479@qq.com"        # 接收人

# ----------2.編輯郵件的內容------ subject = "這個是主題QQ" body = '<p>這個是發送的QQ郵件</p>'     # 定義郵件正文爲html格式 msg = MIMEText(body, "html", "utf-8") msg['from'] = sender msg['to'] = "283340479@qq.com" msg['subject'] = subject
# ----------3.發送郵件------ # smtp = smtplib.SMTP() # smtp.connect(smtpserver)                                 # 連服務器 smtp = smtplib.SMTP_SSL(smtpserver, port) smtp.login(sender, psw)                                      # 登陸 smtp.sendmail(sender, receiver, msg.as_string())  # 發送 smtp.quit()                                                        # 關閉

3、兼容163和QQ郵箱
1.若是想兼容上面兩種方式發送郵件,只需把第三塊內容稍微改下,以下所示

4、發送帶附件
1.上面的MIMEText只能發送正文,沒法帶附件,發送帶附件的須要導入另一個模塊MIMEMultipart
2.先讀取要發送文件的內容,file_path是路徑的參數名
3.下圖紅色框框file_name參數是發送的附件從新命名

4.參考代碼:

# coding:utf-8
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# ----------1.跟發件相關的參數------ smtpserver = "smtp.163.com"           # 發件服務器 port = 0                                           # 端口 sender = "yoyo@163.com"               # 帳號 psw = "***********"                             # 密碼 receiver = "283340479@qq.com"        # 接收人

# ----------2.編輯郵件的內容------ # 讀文件 file_path = "result.html" with open(file_path, "rb") as fp:     mail_body = fp.read() msg = MIMEMultipart() msg["from"] = sender                             # 發件人 msg["to"] = receiver                               # 收件人 msg["subject"] = "這個個人主題"             # 主題 # 正文 body = MIMEText(mail_body, "html", "utf-8") msg.attach(body) # 附件 att = MIMEText(mail_body, "base64", "utf-8") att["Content-Type"] = "application/octet-stream" att["Content-Disposition"] = 'attachment; filename="test_report.html"' msg.attach(att)
# ----------3.發送郵件------ try:     smtp = smtplib.SMTP()     smtp.connect(smtpserver)                      # 連服務器     smtp.login(sender, psw) except:     smtp = smtplib.SMTP_SSL(smtpserver, port)     smtp.login(sender, psw)                       # 登陸 smtp.sendmail(sender, receiver, msg.as_string())  # 發送 smtp.quit()    

5.最後結果,有圖有真相

5、發給多個收件人
1.上面都是發給一個收件人,那麼如何一次發給多個收件人呢?只需改兩個小地方
2.把receiver參數改爲list對象,單個多個都是能夠收到的
3.msg["to"]這個參數不能用list了,得先把receiver參數轉化成字符串,以下圖所示

4.參考代碼:

# coding:utf-8
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# ----------1.跟發件相關的參數------ smtpserver = "smtp.163.com"           # 發件服務器 port = 0                              # 端口 sender = "yoyo@163.com"     # 帳號 psw = "*********"                  # 密碼 # receiver = ["xxxx@qq.com"]      # 單個接收人也能夠是list receiver = ["xxxx@qq.com", "yoyo@qq.com"]   # 多個收件人list對象

# ----------2.編輯郵件的內容------ # 讀文件 file_path = "result.html" with open(file_path, "rb") as fp:     mail_body = fp.read() msg = MIMEMultipart() msg["from"] = sender                       # 發件人 msg["to"] = ";".join(receiver)             # 多個收件人list轉str msg["subject"] = "這個個人主題999"              # 主題 # 正文 body = MIMEText(mail_body, "html", "utf-8") msg.attach(body) # 附件 att = MIMEText(mail_body, "base64", "utf-8") att["Content-Type"] = "application/octet-stream" att["Content-Disposition"] = 'attachment; filename="test_report.html"' msg.attach(att)
# ----------3.發送郵件------ try:     smtp = smtplib.SMTP()     smtp.connect(smtpserver)                      # 連服務器     smtp.login(sender, psw) except:     smtp = smtplib.SMTP_SSL(smtpserver, port)     smtp.login(sender, psw)                       # 登陸 smtp.sendmail(sender, receiver, msg.as_string())  # 發送 smtp.quit()                                       # 關閉

六:郵件收不到的幾種緣由:
1.Subject和正文內容不要用hello、hehe、test等單詞
2.from(發件人)和to(收件人)不要爲空,
  (要否則會被認爲是垃圾郵件)
3.找不到的話,先看下垃圾信箱,是否是跑到垃圾箱了
4.若是前幾回能夠收到,後來收不到了,需改下subject內容
  (由於每次都是一個subject,系統也會拒收的,把subject內容設置爲動態的是最好的)
5.部分郵箱是ssl加密了的,因此沒法發送,如:qq郵箱
(用受權碼去登陸)
6.要是按照上面的步驟來報錯了,說明代碼抄錯了,多檢查幾回。

(以上代碼均在python2和python3上都測試經過了)

3.14 unittest之skip

前言
當測試用例寫完後,有些模塊有改動時候,會影響到部分用例的執行,這個時候咱們但願暫時跳過這些用例。
或者前面某個功能運行失敗了,後面的幾個用例是依賴於這個功能的用例,若是第一步就失敗了,後面的用例也就不必去執行了,直接跳過就行,節省用例執行時間。
1、skip裝飾器
skip裝飾器一共有四個:

@unittest.skip(reason)

Unconditionally skip the decorated test. reason should describe why the test is being skipped.

翻譯:無條件跳過用例,reason是說明緣由。

@unittest.skipIf(condition, reason)

Skip the decorated test if condition is true.

翻譯:condition爲true的時候跳過。

@unittest.skipUnless(condition, reason)

Skip the decorated test unless condition is true.

翻譯:condition爲False的時候跳過。

@unittest.expectedFailure

Mark the test as an expected failure. If the test fails when run, the test is not counted as a failure.

翻譯:斷言的時候跳過。


2、skip案例

運行結果:
測試1
測試4
.ssx

----------------------------------------------------------------------
Ran 4 tests in 0.003s
OK (skipped=2, expected failures=1)
3、跳過整個測試類

4、參考代碼:

# coding:utf-8
import unittest
class Test(unittest.TestCase):
    @unittest.skip(u"無條件跳過此用例")
    def test_1(self):
        print "測試1"
    @unittest.skipIf(True, u"爲True的時候跳過")
    def test_2(self):
        print "測試2"
    @unittest.skipUnless(False, u"爲False的時候跳過")
    def test_3(self):
       print "測試3"
    @unittest.expectedFailure
    def test_4(self):
        print "測試4"
        self.assertEqual(2, 4, msg=u"判斷相等")
if __name__ == "__main__":
    unittest.main()
相關文章
相關標籤/搜索