unittest單元測試框架總結

    unittest單元測試框架不只能夠適用於單元測試,還能夠適用WEB自動化測試用例的開發與執行,該測試框架可組織執行測試用例,而且提供了豐富的斷言方法,判斷測試用例是否經過,最終生成測試結果。今天筆者就總結下如何使用unittest單元測試框架來進行WEB自動化測試。html

 

1、unittest模塊的各個屬性說明python

    先來聊一聊unittest模塊的各個屬性,所謂知己知彼方能百戰百勝,瞭解unittest的各個屬性,對於後續編寫用例有很大的幫助。web

1.unittest的屬性以下:數據庫

['BaseTestSuite', 'FunctionTestCase', 'SkipTest', 'TestCase', 'TestLoader', 'TestProgram', 'TestResult', 'TestSuite', 'TextTestResult', 'TextTestRunner', '_TextTestResult', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__unittest', 'case', 'defaultTestLoader', 'expectedFailure', 'findTestCases', 'getTestCaseNames', 'installHandler', 'loader', 'main', 'makeSuite', 'registerResult', 'removeHandler', 'removeResult', 'result', 'runner', 'signals', 'skip', 'skipIf', 'skipUnless', 'suite', 'util']瀏覽器

說明:緩存

unittest.TestCase:TestCase類,全部測試用例類繼承的基本類。框架

class BaiduTest(unittest.TestCase):

unittest.main():使用她能夠方便的將一個單元測試模塊變爲可直接運行的測試腳本,main()方法使用TestLoader類來搜索全部包含在該模塊中以「test」命名開頭的測試方法,並自動執行他們。執行方法的默認順序是:根據ASCII碼的順序加載測試用例,數字與字母的順序爲:0-9,A-Z,a-z。因此以A開頭的測試用例方法會優先執行,以a開頭會後執行。less

unittest.TestSuite():unittest框架的TestSuite()類是用來建立測試套件的。ssh

unittest.TextTextRunner():unittest框架的TextTextRunner()類,經過該類下面的run()方法來運行suite所組裝的測試用例,入參爲suite測試套件。post

unittest.defaultTestLoader(): defaultTestLoader()類,經過該類下面的discover()方法可自動更具測試目錄start_dir匹配查找測試用例文件(test*.py),並將查找到的測試用例組裝到測試套件,所以能夠直接經過run()方法執行discover。用法以下:

discover=unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')

unittest.skip():裝飾器,當運行用例時,有些用例可能不想執行等,可用裝飾器暫時屏蔽該條測試用例。一種常見的用法就是好比說想調試某一個測試用例,想先屏蔽其餘用例就能夠用裝飾器屏蔽。

@unittest.skip(reason): skip(reason)裝飾器:無條件跳過裝飾的測試,並說明跳過測試的緣由。

@unittest.skipIf(reason): skipIf(condition,reason)裝飾器:條件爲真時,跳過裝飾的測試,並說明跳過測試的緣由。

@unittest.skipUnless(reason): skipUnless(condition,reason)裝飾器:條件爲假時,跳過裝飾的測試,並說明跳過測試的緣由。

@unittest.expectedFailure(): expectedFailure()測試標記爲失敗。

 

2.TestCase類的屬性以下:

['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_addSkip', '_baseAssertEqual', '_classSetupFailed', '_deprecate', '_diffThreshold', '_formatMessage', '_getAssertEqualityFunc', '_truncateMessage', 'addCleanup', 'addTypeEqualityFunc', 'assertAlmostEqual', 'assertAlmostEquals', 'assertDictContainsSubset', 'assertDictEqual', 'assertEqual', 'assertEquals', 'assertFalse', 'assertGreater', 'assertGreaterEqual', 'assertIn', 'assertIs', 'assertIsInstance', 'assertIsNone', 'assertIsNot', 'assertIsNotNone', 'assertItemsEqual', 'assertLess', 'assertLessEqual', 'assertListEqual', 'assertMultiLineEqual', 'assertNotAlmostEqual', 'assertNotAlmostEquals', 'assertNotEqual', 'assertNotEquals', 'assertNotIn', 'assertNotIsInstance', 'assertNotRegexpMatches', 'assertRaises', 'assertRaisesRegexp', 'assertRegexpMatches', 'assertSequenceEqual', 'assertSetEqual', 'assertTrue', 'assertTupleEqual', 'assert_', 'countTestCases', 'debug', 'defaultTestResult', 'doCleanups', 'fail', 'failIf', 'failIfAlmostEqual', 'failIfEqual', 'failUnless', 'failUnlessAlmostEqual', 'failUnlessEqual', 'failUnlessRaises', 'failureException', 'id', 'longMessage', 'maxDiff', 'run', 'setUp', 'setUpClass', 'shortDescription', 'skipTest', 'tearDown', 'tearDownClass']

說明:

setUp():setUp()方法用於測試用例執行前的初始化工做。如測試用例中須要訪問數據庫,能夠在setUp中創建數據庫鏈接並進行初始化。如測試用例須要登陸web,能夠先實例化瀏覽器。

tearDown():tearDown()方法用於測試用例執行以後的善後工做。如關閉數據庫鏈接。關閉瀏覽器。

assert*():一些斷言方法:在執行測試用例的過程當中,最終用例是否執行經過,是經過判斷測試獲得的實際結果和預期結果是否相等決定的。

assertEqual(a,b,[msg='測試失敗時打印的信息']):斷言a和b是否相等,相等則測試用例經過。

assertNotEqual(a,b,[msg='測試失敗時打印的信息']):斷言a和b是否相等,不相等則測試用例經過。

assertTrue(x,[msg='測試失敗時打印的信息']):斷言x是否True,是True則測試用例經過。

assertFalse(x,[msg='測試失敗時打印的信息']):斷言x是否False,是False則測試用例經過。

assertIs(a,b,[msg='測試失敗時打印的信息']):斷言a是不是b,是則測試用例經過。

assertNotIs(a,b,[msg='測試失敗時打印的信息']):斷言a是不是b,不是則測試用例經過。

assertIsNone(x,[msg='測試失敗時打印的信息']):斷言x是否None,是None則測試用例經過。

assertIsNotNone(x,[msg='測試失敗時打印的信息']):斷言x是否None,不是None則測試用例經過。

assertIn(a,b,[msg='測試失敗時打印的信息']):斷言a是否在b中,在b中則測試用例經過。

assertNotIn(a,b,[msg='測試失敗時打印的信息']):斷言a是否在b中,不在b中則測試用例經過。

assertIsInstance(a,b,[msg='測試失敗時打印的信息']):斷言a是是b的一個實例,是則測試用例經過。

assertNotIsInstance(a,b,[msg='測試失敗時打印的信息']):斷言a是是b的一個實例,不是則測試用例經過。

 

3.TestSuite類的屬性以下:(組織用例時須要用到)

['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_addClassOrModuleLevelException', '_get_previous_module', '_handleClassSetUp', '_handleModuleFixture', '_handleModuleTearDown', '_tearDownPreviousClass', '_tests', 'addTest', 'addTests', 'countTestCases', 'debug', 'run']

說明:

addTest(): addTest()方法是將測試用例添加到測試套件中,以下方,是將test_baidu模塊下的BaiduTest類下的test_baidu測試用例添加到測試套件。

suite = unittest.TestSuite()
suite.addTest(test_baidu.BaiduTest('test_baidu'))
 

4.TextTextRunner的屬性以下:(組織用例時須要用到)

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_makeResult', 'buffer', 'descriptions', 'failfast', 'resultclass', 'run', 'stream', 'verbosity']

說明:

run(): run()方法是運行測試套件的測試用例,入參爲suite測試套件。

runner = unittest.TextTestRunner()
runner.run(suite)

 

2、使用unittest框架編寫測試用例思路

設計基本思路以下:

複製代碼
# coding=utf-8
#1.先設置編碼,utf-8可支持中英文,如上,通常放在第一行

#2.註釋:包括記錄建立時間,建立人,項目名稱。
'''
Created on 2016-7-27
@author: Jennifer
Project:使用unittest框架編寫測試用例思路
'''
#3.導入unittest模塊
import unittest

#4.定義測試類,父類爲unittest.TestCase。
#可繼承unittest.TestCase的方法,如setUp和tearDown方法,不過此方法能夠在子類重寫,覆蓋父類方法。
#可繼承unittest.TestCase的各類斷言方法。
class Test(unittest.TestCase): 
    
#5.定義setUp()方法用於測試用例執行前的初始化工做。
#注意,全部類中方法的入參爲self,定義方法的變量也要「self.變量」
#注意,輸入的值爲字符型的須要轉爲int型
    def setUp(self):
        self.number=raw_input('Enter a number:')
        self.number=int(self.number)

#6.定義測試用例,以「test_」開頭命名的方法
#注意,方法的入參爲self
#可以使用unittest.TestCase類下面的各類斷言方法用於對測試結果的判斷
#可定義多個測試用例
#最重要的就是該部分
    def test_case1(self):
        print self.number
        self.assertEqual(self.number,10,msg='Your input is not 10')
        
    def test_case2(self):
        print self.number
        self.assertEqual(self.number,20,msg='Your input is not 20')

    @unittest.skip('暫時跳過用例3的測試')
    def test_case3(self):
        print self.number
        self.assertEqual(self.number,30,msg='Your input is not 30')

#7.定義tearDown()方法用於測試用例執行以後的善後工做。
#注意,方法的入參爲self
    def tearDown(self):
        print 'Test over'
        
#8若是直接運行該文件(__name__值爲__main__),則執行如下語句,經常使用於測試腳本是否可以正常運行
if __name__=='__main__':
#8.1執行測試用例方案一以下:
#unittest.main()方法會搜索該模塊下全部以test開頭的測試用例方法,並自動執行它們。
#執行順序是命名順序:先執行test_case1,再執行test_case2
    unittest.main()

'''
#8.2執行測試用例方案二以下:
#8.2.1先構造測試集
#8.2.1.1實例化測試套件
    suite=unittest.TestSuite()
#8.2.1.2將測試用例加載到測試套件中。
#執行順序是安裝加載順序:先執行test_case2,再執行test_case1
    suite.addTest(Test('test_case2'))
    suite.addTest(Test('test_case1'))
#8.2.2執行測試用例
#8.2.2.1實例化TextTestRunner類
    runner=unittest.TextTestRunner()
#8.2.2.2使用run()方法運行測試套件(即運行測試套件中的全部用例)
    runner.run(suite)
''' ''' #8.3執行測試用例方案三以下: #8.3.1構造測試集(簡化了方案二中先要建立測試套件而後再依次加載測試用例) #執行順序同方案一:執行順序是命名順序:先執行test_case1,再執行test_case2 test_dir = './' discover = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py') #8.3.2執行測試用例 #8.3.2.1實例化TextTestRunner類 runner=unittest.TextTestRunner() #8.3.2.2使用run()方法運行測試套件(即運行測試套件中的全部用例) runner.run(discover) '''
複製代碼

使用方案一執行測試用例結果以下:

Enter a number:10
10
Test over
Enter a number:.10
Fs

Ran 3 tests in 6.092s

FAILED (failures=1, skipped=1)
10
Test over

由於先執行test_case1,再執行test_case2,因此第一次輸入10時,執行經過,返回. 第二次輸入10時,執行不經過,返回F,最終一個用例經過,一個用例失敗,還有一個用例是直接跳過的(裝飾器)。

 使用方案二執行測試用例結果以下:

Enter a number:10
10
Test over
Enter a number:F10
.

Ran 2 tests in 4.973s

FAILED (failures=1) 
10
Test over

由於先執行test_case2,再執行test_case1,因此第一次輸入10時,執行不經過,返回F , 第二次輸入10時,執行經過,返回. ,最終一個用例經過,一個用例失敗。

使用方案三執行測試用例結果以下(執行測試用例順序同方案一):

Enter a number:10
10
Test over
Enter a number:.10
Fs

Ran 3 tests in 6.092s

FAILED (failures=1, skipped=1)
10
Test over

由於先執行test_case1,再執行test_case2,因此第一次輸入10時,執行經過,返回. 第二次輸入10時,執行不經過,返回F,最終一個用例經過,一個用例失敗,還有一個用例是直接跳過的(裝飾器)。

 

3、使用unittest框架編寫測試用例實例

 

目錄結構:

百度搜索測試用例Test Case:

複製代碼
# coding=utf-8
'''
Created on 2016-7-22
@author: Jennifer
Project:登陸百度測試用例
'''
from selenium import webdriver
import unittest, time

class BaiduTest(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30) #隱性等待時間爲30秒
        self.base_url = "https://www.baidu.com"
    
    def test_baidu(self):
        driver = self.driver
        driver.get(self.base_url + "/")
        driver.find_element_by_id("kw").clear()
        driver.find_element_by_id("kw").send_keys("unittest")
        driver.find_element_by_id("su").click()
        time.sleep(3)
        title=driver.title
        self.assertEqual(title, u"unittest_百度搜索") 

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

if __name__ == "__main__":
    unittest.main()
複製代碼

有道翻譯測試用例Test Case:

複製代碼
# coding=utf-8
'''
Created on 2016-7-22
@author: Jennifer
Project:使用有道翻譯測試用例
'''
from selenium import webdriver
import unittest, time

class YoudaoTest(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30) #隱性等待時間爲30秒
        self.base_url = "http://www.youdao.com"
    
    def test_youdao(self):
        driver = self.driver
        driver.get(self.base_url + "/")
        driver.find_element_by_id("translateContent").clear()
        driver.find_element_by_id("translateContent").send_keys(u"你好")
        driver.find_element_by_id("translateContent").submit()
        time.sleep(3)
        page_source=driver.page_source
        self.assertIn( "hello",page_source) 

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

if __name__ == "__main__":
    unittest.main()
複製代碼

web測試用例:經過測試套件TestSuite來組裝多個測試用例。

複製代碼
# coding=utf-8
'''
Created on 2016-7-26
@author: Jennifer
Project:編寫Web測試用例
'''
import unittest
from test_case import test_baidu
from test_case import test_youdao

#構造測試集
suite = unittest.TestSuite()
suite.addTest(test_baidu.BaiduTest('test_baidu'))
suite.addTest(test_youdao.YoudaoTest('test_youdao'))

if __name__=='__main__':
    #執行測試
    runner = unittest.TextTestRunner()
    runner.run(suite)
複製代碼

測試結果:

說明:.表明用例執行經過,兩個點表示兩個用例執行經過。F表示用例執行不經過。

 

命令行

unittest模塊支持從命令行運行模塊中的測試、類,甚至是單獨的測試方法。

  1.  
    python -m unittest test_module1 test_module2
  2.  
    python -m unittest test_module.TestClass
  3.  
    python -m unittest test_module.TestClass.test_method

模塊也能夠是帶路徑的方式:

python -m unittest tests/test_something.py

你也可使用文件名代替測試模塊名。指定的文件必須是可導入的。路徑就是去掉「.py」後的文件名,文件名和模塊名之間使用「.」鏈接。若是你要執行的測試文件不能被做爲模塊導入,也能夠直接執行該文件。

經過傳入-v選項,你能夠查看更多的執行細節:

python -m unittest -v test_module

當命令行中不傳入任何執行目標時,默認執行Test Discovery中的測試:

python -m unittest

查看全部命令參數:

python -m unittest -h

該功是能在3.2版本中新增的。早期的版本只能運行單獨的測試方法,不能運行模塊和測試類。

命令行選項,unittest支持如下命令行選項:

-b,--buffer

當測試在運行時,輸出的錯誤信息被緩存在內存中,若是測試運行經過,則釋放緩存,若是測試失敗,信息就會被打印出來。

-c,--catch

在測試執行時按下Control-C將會等待當前測試完成並輸入全部測試報告。第二次按下Control-C就會觸發KeyboardInterrupt異常。

-f,--failfast

測試一旦出現錯誤或失敗就中止運行。

--locals

在異常回溯中打印本地變量信息。

命令行選項-b、-c和-f在3.2版本中新增。

命令行選項--locals在3.5版本中新增。

命令行選項也能夠在Test Discovery中使用,全部項目中的測試均可以使用。

Test Discovery

3.2版本中新增。

unittest支持簡單的測試發現功能。爲了兼容test discovery,全部的測試文件必須是能從項目的頂層目錄導入的模塊或包(包括命名空間包),意思就是文件名必須是有效的標識符。

Test Discovery在TestLoader.discover()中實現,可是仍能用於命令行模式。基本使用方法以下:

  1.  
    cd project_directory
  2.  
    python -m unittest discover

注意:python -m unittest雖然做用和python -m unittest discovery同樣。可是若是要傳遞參數給discover的話仍是要寫完整的命令。

選項:

-v,--verbose

詳細的輸出

-s,--start-directory 目錄

Discovery尋找的其實目錄(默認.)

-p,--pattern 模式

匹配的測試文件的格式(默認test*.py)

-t,--top-level-directory 目錄

項目的頂級目錄(directory的默認起始目錄)

-s,-p和-t選項能夠做爲位置參數,如下兩個命令是等效的:

  1.  
    python -m unittest discover -s project_directory -p "*_test.py"
  2.  
    python -m unittest discover project_directory "*_test.py"

可使用傳遞一個包名路徑,好比 myproject.subpackage.test做爲初始目錄。這樣的話,這個包就會被導入,包的路徑就會被當作初始目錄。

注意:Discovery經過導入的方式來加載測試。一旦test discovery從你提供的初始目錄中發現了全部的測試文件,它就會將路徑轉換成包名導入,好比foo/bar/baz.py會被當作foo.bar.baz進行導入。

若是你有一個在公共的包而且使用test discovery去加載該包的另外一個不一樣副本,那麼就會引起異常,致使discovery退出。

若是你提供了一個起始目錄做爲包名稱而不是提供一個路徑做爲目錄,那麼discovery就會認爲全部位置的文件都是你須要導入的(包括中間路徑),這樣就不會報錯。

測試模塊和包經過load_tests協議以指定的方式加載測試和運行discover。

3.4版本中修改:Test discovery支持命名空間包。

 

#Method 1
if __name__ == '__main__':
    print("main")
    report_title = '百度測試報告'
    desc = '用於展現修改樣式後的HTMLTestRunner'
    report_file = 'ExampleReport.html'

    # Shift+Alt+F10 纔會生成報告
    suite = unittest.TestLoader().loadTestsFromTestCase(case_01)
    now = time.strftime("%Y-%m-%d_%H_%M_%S")

    with open(report_file, 'wb') as report:

        runner = HTMLTestRunner(
            title=report_title,
            description=desc,
            stream=report,
            verbosity=2,
            retry=0,
            save_last_try=True)
        runner.run(suite)


#Method 2 運行全部的測試用例
if __name__ == '__main__':
    print("main")
    unittest.main()

#Method 3
if __name__ == '__main__':
    print("main")
    suit = unittest.TestSuite() #建立一個測試集合
    suit.addTest(case_01("test_run1")) #測試套件中添加測試用例
#   test_suite.addTest(unittest.makeSuite(case_01))#使用makeSuite方法添加全部的測試方法
    suit.addTest(case_01("test_run2"))
    suit.addTest(case_01("test_run3"))


    filename =  'ExampleReport.html'
    fp = open(filename, 'wb') #打開一個保存結果的html文件
    #生成執行用例的對象
    runner = HTMLTestRunner(stream=fp,
                            title='Test Report',
                            description='Implementation Example with: ')
    #執行測試套件
    runner.run(suit)
    fp.close


#Method 4
if __name__=='__main__':
    print("main")
    #test_dir='/Users/chenqi1/Pycharm/study/PracticeFile/'
    all_cases=unittest.defaultTestLoader.discover('.', 'test_*.py')
    runner=unittest.TextTestRunner()
    runner.run(all_cases)

# #Method 5
if __name__=='__main__':
    print("main")

    suite = unittest.TestSuite()#建立測試套件
    all_cases = unittest.defaultTestLoader.discover('.','test_*.py')
    #找到某個目錄下全部的以test開頭的Python文件裏面的測試用例
    for case in all_cases:
        suite.addTests(case)#把全部的測試用例添加進來
    fp = open('ExampleReport.html','wb')
    runner = HTMLTestRunner(stream=fp,title='all_tests',description='全部測試狀況')
    runner.run(suite)
    #運行測試
相關文章
相關標籤/搜索