Python接口測試之unittest框架(五)


       Test-driven development(TDD)開發模式在今天已經不是什么新奇的事了,它的開發思維是在開發一個產品功能的時候,先

編寫好該功能的測試代碼,在編寫開發比如,比如要寫二個數相除的函數,那么它的測試代碼應該為:

#!/usr/bin/env python
#coding:utf-8

import  unittest

class TestDiv(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def test_001(self):
        self.assertEqual(div(1,1),1)

    def test_002(self):
        self.assertRaises(ZeroDivisionError,div,1,0)

if __name__=='__main__':
    unittest.main(verbosity=2)

執行如上的代碼,會提示如下NameError: global name 'div' is not defined的錯誤信息,事實上我們自己也是

非常明白,因為我們實際沒有實現這樣的一個函數,而是先寫了改函數功能的測試代碼,那么現在來寫函數部分,見

完善后的源碼:

#!/usr/bin/env python
#coding:utf-8


def div(a,b):
    return a/b

import  unittest

class TestDiv(unittest.TestCase):
    def setUp(self):
        pass

    def tearDown(self):
        pass

    def test_001(self):
        self.assertEqual(div(1,1),1)

    def test_002(self):
        self.assertRaises(ZeroDivisionError,div,1,0)

if __name__=='__main__':
    unittest.main(verbosity=2)

 

再次執行我們的測試代碼,就會通過,見執行的結果結果:

這就是一個測試驅動的過程,關於測試驅動的開發模式以及實戰部分,建議看《Python Web開發測試驅動方法》這本書,在

里面作者圍繞Django的框架,有詳細的案例介紹和代碼論述。在這里我們只關注unittest框架,這也是本文章要總結的的部分。

    不論對於開發還是測試,都離不開單元測試框架,對於開發而言使用單元測試框架,可以編寫測試代碼來驗證驗證自己編寫

的功能是否正確,對於測試而言,使用單元測試框架,可以編寫自動化的測試用例,在Python中單元測試框架是Pyunit,即

unittest,unittest我一直認為是一個很優秀的單元測試框架,至少我是這樣認為在,它是python的標准庫,官方詳細的地址

是:https://docs.python.org/2/library/unittest.html單元測試支持測試自動化 共享安裝程序關閉代碼測試 

聚合集合測試報告框架測試獨立性單元測試模塊提供可以容易支持這些素質測試。關於unittest

測試框架建議可以到官方查看詳細的說明以及演示的實例。unittest各個模塊的關系為:

 

在一個完整的單元測試用例中,是包含了測試固件(setUp()和tearDown()),在測試執行的階段,我們更加願意使用測試

套件(TestSuite())來組織每個測試用例來執行(TestRunner)並得到測試結果(TestReport),什么 是測試固件,在

unittest中,setUp()與tearDown()被成為測試固件,某些人稱為鈎子(僅僅只一個稱呼而已),它的主要目標初始化

測試用例,執行測試用例后,對測試用例執行的結果做后期的處理,我們再看上面的測試用例,總共是二個測試用例,

不管執行那個測試用例,都會執行setUp()和tearDown(),也就是說,在一個測試類中,如果有N個測試用例,在執行

該測試類中的測試用例的時候,會執行N次setUp()和tearDown(),我們修改源碼並執行來看結果,見源碼:

#!/usr/bin/env python
#coding:utf-8


def div(a,b):
    return a/b

import  unittest

class TestDiv(unittest.TestCase):
    def setUp(self):
        print u'開始...'

    def tearDown(self):
        print u'結束...'

    def test_001(self):
        self.assertEqual(div(1,1),1)

    def test_002(self):
        self.assertRaises(ZeroDivisionError,div,1,0)

if __name__=='__main__':
    unittest.main(verbosity=2)

 

見執行的結果截圖:

依據結果可以看到,執行了二個測試用例,也執行了2次setUp()和tearDown()方法,如果這樣你感覺不明顯,可以結合

selenium的測試框架來看更加直觀,見源碼:

#!/usr/bin/env python
#coding:utf-8


def div(a,b):
    return a/b

import  unittest
from selenium import  webdriver

class TestDiv(unittest.TestCase):
    def setUp(self):
        self.driver=webdriver.Firefox()
        self.driver.get('http://www.baidu.com')

    def tearDown(self):
        self.driver.quit()

    def test_001(self):
        self.assertEqual(self.driver.title,u'百度一下,你就知道')

    def test_002(self):
        self.assertEqual(self.driver.current_url,'https://www.baidu.com/')

if __name__=='__main__':
    unittest.main(verbosity=2)

 

 執二后,會看到打開瀏覽器二次,當然關閉瀏覽器也是二次,這里不在進行截圖了。那么可不可以讓測試固件只執行

一次了,也就是說在一個測試類中,有N個測試用例,執行這個測試類中的測試用例后,測試固件只執行一次。當然是

可以的,unittest提供了這樣的解決方案,在這里鈎子方法使用的是類方法(關於實例方法,類方法,靜態方法不熟悉

的建議看下python的OOP部分),我們重構下代碼來實現這樣的一個過程,見源碼:

#!/usr/bin/env python
#coding:utf-8

import  unittest
from selenium import  webdriver

class TestDiv(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver=webdriver.Firefox()
        cls.driver.get('http://www.baidu.com')

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

    def test_001(self):
        self.assertEqual(self.driver.title,u'百度一下,你就知道')

    def test_002(self):
        self.assertEqual(self.driver.current_url,'https://www.baidu.com/')

if __name__=='__main__':
    unittest.main(verbosity=2)

 

       OK,帶着疑問繼續觸發,在一個測試用例中,測試用例想有順序的執行該如何實現了,可以使用addTest()方法來實現,

也就是說,把需要執行的或者按順序的添加到測試套件中,見修改后的源碼:

#!/usr/bin/env python
#coding:utf-8

import  unittest
from selenium import  webdriver

class TestDiv(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver=webdriver.Firefox()
        cls.driver.get('http://www.baidu.com')

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

    def test_001(self):
        self.assertEqual(self.driver.title,u'百度一下,你就知道')

    def test_002(self):
        self.assertEqual(self.driver.current_url,'https://www.baidu.com/')

if __name__=='__main__':
    suite=unittest.TestSuite()
    suite.addTest(TestDiv('test_001'))
    unittest.TextTestRunner(verbosity=2).run(suite)

 或者我們可以把代碼重構為:

#!/usr/bin/env python
#coding:utf-8

import  unittest
from selenium import  webdriver

class TestDiv(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver=webdriver.Firefox()
        cls.driver.get('http://www.baidu.com')

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

    def test_001(self):
        self.assertEqual(self.driver.title,u'百度一下,你就知道')

    def test_002(self):
        self.assertEqual(self.driver.current_url,'https://www.baidu.com/')

    @staticmethod
    def suites():
        tests=['test_001','test_002']
        return unittest.TestSuite(map(TestDiv,tests))


if __name__=='__main__':
    unittest.TextTestRunner(verbosity=2).run(TestDiv.suites())

 

事實上,我個人不贊成使用addTest()方法,來把測試用例依次添加到測試套件中,理由非常簡單,

因為在一個測試類中,測試用例是非常多的,這樣添加或者刪除實在是浪費時間,我們可以把源碼

修改下,來實現執行一個測試,某些用例不執行的可以忽略,使用的方法是makeSuite(),見修改后

的源碼:

#!/usr/bin/env python
#coding:utf-8

import  unittest
from selenium import  webdriver

class TestDiv(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver=webdriver.Firefox()
        cls.driver.get('http://www.baidu.com')

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

    def test_001(self):
        self.assertEqual(self.driver.title,u'百度一下,你就知道')

    @unittest.skip(u'忽略該測試用例,謝謝!')
    def test_002(self):
        self.assertEqual(self.driver.current_url,'https://www.baidu.com/')

if __name__=='__main__':
    suite=unittest.TestSuite(unittest.makeSuite(TestDiv))
    unittest.TextTestRunner(verbosity=2).run(suite)

 

見執行后的截圖:

在這里總結的,只是個人喜好,每個人可以根據自己的實際情況來進行,這只是提供了一種選擇而已。還有另外

一種方法是TestLoader()加載測試類來執行測試類中的所有測試用例,見源碼:

#!/usr/bin/env python
#coding:utf-8

import  unittest
from selenium import  webdriver

class TestDiv(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver=webdriver.Firefox()
        cls.driver.get('http://www.baidu.com')

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

    def test_001(self):
        self.assertEqual(self.driver.title,u'百度一下,你就知道')

    def test_002(self):
        self.assertEqual(self.driver.current_url,'https://www.baidu.com/')

if __name__=='__main__':
    suite=unittest.TestLoader().loadTestsFromTestCase(TestDiv)
    unittest.TextTestRunner(verbosity=2).run(suite)

 

      在一個測試用例中,會有期望結果這個說法,來驗證這個測試用例是通過還是失敗,在unittest的測試框架

中,也提供了assert,我們先來看python中的斷言assert,來修改下源碼,看看python實際代碼的斷言,見

源碼:

#!/usr/bin/env python
#coding:utf-8

import  unittest
from selenium import  webdriver

class TestDiv(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver=webdriver.Firefox()
        cls.driver.get('http://www.baidu.com')

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

    def test_001(self):
        assert self.driver.title in u'百度一下,你就知道'

    def test_002(self):
        assert self.driver.current_url in 'https://www.baidu.com/'

if __name__=='__main__':
    suite=unittest.TestLoader().loadTestsFromTestCase(TestDiv)
    unittest.TextTestRunner(verbosity=2).run(suite)

見執行的結果的截圖:

上面的僅僅是python語言自帶的assert,在unittest中提供了非常豐富的斷言,具體見如下的截圖:

下面就演示幾個斷言的使用方法,見案例的源碼:

#!/usr/bin/env python
#coding:utf-8

import  unittest
from selenium import  webdriver

class TestDiv(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver=webdriver.Firefox()
        cls.driver.get('http://www.baidu.com')

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

    def test_001(self):
        self.assertEqual(self.driver.title, u'百度一下,你就知道')

    def test_002(self):
        self.assertTrue(self.driver.find_element_by_id('kw').is_enabled())

    def test_003(self):
        self.assertIsNot(self.driver.current_url,'www.baidu.com')

if __name__=='__main__':
    suite=unittest.TestLoader().loadTestsFromTestCase(TestDiv)
    unittest.TextTestRunner(verbosity=2).run(suite)

見執行后的結果:

unittest的斷言是非常豐富的,這里就不在演示了,遇到了不知道,可以到官方查看。

    在python中,提供了HTMLTestRunner.py來生成測試報告,把該文件下載后,直接放到C:\Python27\Lib的目錄下,

就可以導入該模塊使用了,見該實現的代碼:

#!/usr/bin/env python
#coding:utf-8

import  unittest
from selenium import  webdriver
import  HTMLTestRunner

class TestDiv(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver=webdriver.Firefox()
        cls.driver.get('http://www.baidu.com')

    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()

    def test_001(self):
        self.assertEqual(self.driver.title, u'百度一下,你就知道')

    def test_002(self):
        self.assertTrue(self.driver.find_element_by_id('kw').is_enabled())

    def test_003(self):
        self.assertIsNot(self.driver.current_url,'www.baidu.com')

if __name__=='__main__':
    suite=unittest.TestLoader().loadTestsFromTestCase(TestDiv)
    runner=HTMLTestRunner.HTMLTestRunner(
        stream=file('testReport.html','wb'),
        title=u'TestReport',
        description=u'測試報告詳細信息'
    )
    runner.run(suite)

執行后,會在當前目錄下生成testReport.html的測試報告,見該報告的截圖:

python的unittest庫非常強大,這里只是介紹了一部分,詳細的可以到官方繼續查看或者關注本人的公眾號咨詢互相學習。如您對我寫的內容感興趣,可掃描關注本人的微信公眾,

祝安!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM