selenium自動化測試、Python單元測試unittest框架以及測試報告和日志輸出


部分內容來自:https://www.cnblogs.com/klb561/p/8858122.html

一、基礎介紹

 核心概念:test case, testsuite, TestLoder,TextTestRunner,TextTestResult, test fixture

TestCase(測試用例): 所有測試用例的基類,它是軟件 測試中最基本的組成單元。

 一個test case就是一個測試用例,是一個完整的測試流程,包括測試前環境的搭建setUp,執行測試代碼(run),以及測試后環境的還原(tearDown)。測試用例是一個完整的測試單元,可以對某一問題進行驗證。

TestSuite(測試套件):多個測試用例test case集合就是TestSuite,TestSuite可以嵌套TestSuite

TestLoder:是用來加載 TestCase到TestSuite中,其中有幾個loadTestsFrom_()方法,就是從各個地方尋找TestCase,創建他們的實例,然后add到TestSuite中,再返回一個TestSuite實例

TextTestRunner:是來執行測試用例的,其中的run(test)會執行TestSuite/TestCase中的run(result)方法。

 TextTestResult:測試結果會保存到TextTestResult實例中,包括運行了多少用例,成功與失敗多少等信息

TestFixture:又叫測試腳手,測試代碼的運行環境,指測試准備前和執行后要做的工作,包括setUp和tearDown方法

二、測試流程

1)unittest是Python自帶的單元測試框架,我們可以用其來作為我們自動化測試框架的用例組織執行框架。

2)unittest的流程:寫好TestCase,然后由TestLoader加載TestCase到TestSuite,然后由 TextTestRunner來運行TestSuite,運行的結果保存在TextTestResult中,我們通過命令行或者unittest.main()執行時,main會調用TextTestRunner中的run來執行,或者我們可以直接通過 TextTestRunner來執行用例。

3)一個class繼承unittest.TestCase即是一個TestCase,其中以 test 開頭的方法在load時被加載為一個真正的TestCase。

4)verbosity參數可以控制執行結果的輸出,0 是簡單報告、1 是一般報告、2 是詳細報告。

5)可以通過addTest和addTests向suite中添加case或suite,可以用TestLoader的loadTestsFrom__()方法。

6)用 setUp()tearDown()setUpClass()以及 tearDownClass()可以在用例執行前布置環境,以及在用例執行后清理環境

7)我們可以通過skip,skipIf,skipUnless裝飾器跳過某個case,或者用TestCase.skipTest方法。

8)參數中加stream,可以將報告輸出到文件:可以用TextTestRunner輸出txt報告,以及可以用HTMLTestRunner輸出html報告。

三、unittest模塊的各個屬性說明

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開頭會后執行。

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

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

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)

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

設計基本思路如下,新建一個test.py文件(名稱自定義),代碼如下

 1 import unittest
 2 
 3 
 4 class Test(unittest.TestCase):
 5     # 定義測試類,父類為unittest.TestCase
 6     # 定義setUp()方法用於測試用例執行前的初始化工作。
 7     def setUp(self):
 8         # 注意,所有類中方法的入參為self,定義方法的變量也要“self.變量”
 9         self.number = input('Enter a number:')
10         self.number = int(self.number)  # 注意,輸入的值為字符型的需要轉為int型
11 
12     # 定義測試用例,以“test_”開頭命名的方法,方法的入參為self
13     # 可定義多個測試用例
14     # 最重要的就是該部分
15     def test_case1(self):
16         self.assertEqual(self.number, 10, msg = 'Your input is not 10')
17 
18     def test_case2(self):
19         print(self.number)
20         self.assertEqual(self.number, 20, msg = 'Your input is not 20')
21 
22     @unittest.skip('暫時跳過用例3的測試')
23     def test_case3(self):
24         print(self.number)
25         self.assertEqual(self.number, 30, msg = 'Your input is not 30')
26 
27     # 定義tearDown()方法用於測試用例執行之后的善后工作。
28     # 注意,方法的入參為self
29     def tearDown(self):
30         print('Test over')
31 
32 
33 # 執行測試用例方案一如下:
34 # unittest.main()方法會搜索該模塊下所有以test開頭的測試用例方法,並自動執行它們。
35 # 執行順序是命名順序:先執行test_case1,再執行test_case2
36 if __name__ == '__main__':
37     unittest.main()
38 
39 # 執行測試用例方案二如下(以下整段代碼塊替換方案一的代碼塊):
40 # 1.先構造測試集2.實例化測試套件
41 if __name__ == '__main__':
42     suite = unittest.TestSuite()
43     # 將測試用例加載到測試套件中。
44     # 執行順序是安裝加載順序:先執行test_case2,再執行test_case1
45     suite.addTest(Test('test_case2'))
46     suite.addTest(Test('test_case1'))
47     # 執行測試用例,實例化TextTestRunner類,verbosity參數可以控制執行結果的輸出,0 是簡單報告、1 是一般報告、2 是詳細報告
48     runner = unittest.TextTestRunner(verbosity = 2)
49     # 使用run()方法運行測試套件(即運行測試套件中的所有用例)
50     runner.run(suite)
51 
52 # 執行測試用例方案三如下(以下整段代碼塊替換方案一的代碼塊):
53 # 構造測試集(簡化了方案二中先要創建測試套件然后再依次加載測試用例)
54 # 執行順序同方案一:執行順序是命名順序:先執行test_case1,再執行test_case2
55 if __name__ == '__main__':
56     test_dir = './'
57     # 通過該類下面的discover()方法可自動加載測試目錄test_dir匹配查找測試用例文件(test_*.py),並將查找到的測試用例組裝到測試套件discover中
58     discover = unittest.defaultTestLoader.discover(test_dir, pattern = 'test_*.py')
59     runner = unittest.TextTestRunner()
60     runner.run(discover)

執行py文件:python test.py

結果:

方案一:因為先執行test_case1,再執行test_case2,所以第一次輸入10時,執行通過,返回. 第二次輸入10時,執行不通過,返回F,最終一個用例通過,一個用例失敗,還有一個用例是直接跳過的(裝飾器)

方案二:因為先執行test_case2,再執行test_case1,所以第一次輸入10時,執行不通過,返回F , 第二次輸入10時,執行通過,返回. ,最終一個用例通過,一個用例失敗。

方案三:因為先執行test_case1,再執行test_case2,所以第一次輸入10時,執行通過,返回. 第二次輸入10時,執行不通過,返回F,最終一個用例通過,一個用例失敗,還有一個用例是直接跳過的(裝飾器)。

五、測試報告輸出:

1. 那如何生成一個測試報告呢,需要加入另外一個模塊了,HTMLTestRunner,這個模塊需要自己安裝,使用執行測試用例就會生成一個html的測試報告

HTMLTestRunner地址:http://tungwaiyip.info/software/HTMLTestRunner.html

注意區分python的版本:2.x與3.x

下載完成后,放到C:\python35\Lib路徑里面,然后修改test.py文件

import HTMLTestRunner #導入報告模塊

#在if __name__ == '__main__'代碼塊中,用下面代碼塊替換runner = unittest.TextTestRunner() with open('HTMLReport.html', 'w') as f: runner = HTMLTestRunner(stream=f, title='MathFunc Test Report', description='generated by HTMLTestRunner.', verbosity=2 ) runner.run(suite)

再執行test.py文件后,后在test.py所在目錄中生成HTMLReport.html;這個路徑可以自行指定

六、測試日志輸出:

1. 可以在運行的時候輸出日志文件,這個不是那么必要

修改test.py

 1 import unittest
 2 import time,os,sys,logging
 3 
 4 sys.path.append(os.path.dirname(os.path.abspath(__file__)) + r'\..')  # 返回腳本的路徑
 5 logging.basicConfig(level=logging.DEBUG,
 6                     format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
 7                     datefmt='%a, %d %b %Y %H:%M:%S',
 8                     filename='log_test.log',
 9                     filemode='w')
10 logger = logging.getLogger()
11 class Test(unittest.TestCase):
12     #代碼略

執行test.py文件后,后在test.py所在目錄中生產log_test.log

在上面代碼塊中的第5行:

INFO:處理請求或者狀態變化等日常事務(一般詳細)
DEBUG:調試過程中使用DEBUG等級,如算法中每個循環的中間狀態(較詳細)

七、總代碼示例:

1. Tset.py文件

# -*- coding:utf-8 -*-

import unittest
import time,os,sys,logging
import HTMLTestRunner

sys.path.append(os.path.dirname(os.path.abspath(__file__)) + r'\..')  # 返回腳本的路徑
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%a, %d %b %Y %H:%M:%S',
                    filename='log_test.log',
                    filemode='w')
logger = logging.getLogger()
class MyTest(unittest.TestCase):  # 繼承unittest.TestCase

    def setUp(self):
        # 每個測試用例執行之前做操作
        print('執行用例開始')

    def tearDown(self):
        # 每個測試用例執行之后做操作
        print('執行用例結束')

    @classmethod
    def tearDownClass(self):
        # 必須使用 @ classmethod裝飾器, 所有test運行完后運行一次
        print('--------測試執行結束--------')

    @classmethod
    def setUpClass(self):
        # 必須使用@classmethod 裝飾器,所有test運行前運行一次
        print('--------測試執行開始--------')

    def test_1_add(self):
        """添加類別信息"""
        logger.info("Now: %r", '執行添加')
        self.assertEqual(1, 1)

    def test_2_que(self):
        """查詢類別信息"""
        logger.info("Now: %r", '執行查詢')
        self.assertEqual(2, 2)

if __name__ == '__main__':
    current_time = time.strftime("%Y-%m-%d-%H_%M_%S", time.localtime(time.time()))
    test_suite = unittest.TestSuite()  # 創建一個測試集合
    test_suite.addTest(MyTest('test_1_add'))
    test_suite.addTest(MyTest('test_2_que'))# 測試套件中添加測試用例
    # test_suite.addTest(unittest.makeSuite(MyTest))#使用makeSuite方法添加所有的測試方法
    report_path = current_time + '.html'  # 生成測試報告的路徑
    fp = open(report_path, "wb")
    runner = HTMLTestRunner.HTMLTestRunner(stream = fp,
                                           title = '自動化測試報告',
                                           description = '用例執行情況:',
                                           verbosity = 2)
    runner.run(test_suite)
    fp.close()

 


免責聲明!

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



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