自動化(五)

Arlick發表於2020-10-21

一、UnitTest

1.1 為什麼使用UnitTest框架?
	1. 批量執行用例
	2. 提供豐富的斷言知識
	3. 可以生成報告

1.2 什麼是UnitTest框架
	python自帶一種單元測試框架

核心要素
TestCase:一條測試用例
TestSuite:測試套件
TestRunner:以文字的形式執行測試用例
TestLoader:批量執行測試用例,搜尋指定資料夾內指定字母開頭的模組
Fixture:固定裝置(兩個固定的函式,一個初始化時使用,一個結束時使用)

1)TestCase

TestCase:
	說明:測試用例
	步驟:
		1. 導包 import unittest
		2. 新建測試類並繼承 unittest.TestCase
		3. 測試方法必須以test字母開頭
		4. 測試檔案也需要以test字母開頭
	執行:
		1. 執行測試類所有的測試方法,游標定位到類當前行右鍵執行
		2. 執行單個測試方法:游標放到測試方法當前行。

__name__: 為python中內建變數
    值:
        1. 如果當前執行的模組為當前模組,那麼__name__的值為:__main__
        2. 如果當前執行的模組不是主模組,那麼__name__的值為:模組名稱

案例:

# 導包
import unittest

# 編寫求和函式
def add(x,y):
    return x+y

# 定義測試類   並   繼承
class Test01(unittest.TestCase):
    # 定義測試,以test字母開頭
    def test_add(self):
        # 呼叫要測試的函式
        result = add(1,1)
        print("結果為:",result)

    def test_add02(self):
        result = add(1,2)
        print("結果為:",result)
        print("\n\n\n")

在這裡插入圖片描述

2)TestSuite(測試套件)與TextTestRunner(測試執行)

在這裡插入圖片描述
在這裡插入圖片描述

TestSuite:
	說明:測試套件 
	步驟: 
		1. 導包
		2. 獲取測試套件物件 suite = unittest.TestSuite()
		3. 呼叫addTest()方法 新增測試用例
		
	新增測試用例方法: 
		1. suite.addTest(類名("方法名稱")) # 新增指定類中指定的測試方法
		2. suite.addTest(unittest.makeSuite(類名)) # 新增指定類中所有已test開頭的方法

TextTestRunner:
	說明:執行測試套件方法
	步驟: 
		1. 導包
		2. 例項化後去執行套件物件 runner = unittest.TextTestRunner()
		3. 呼叫run方法去執行 runner.run(suite)

test_01

import unittest  # 匯入unittest模組

#建立一個繼承unittest.TestCase的類

class Test02(unittest.TestCase):
    # 建立test_為字首的方法
    def test01(self):
        print("test01執行")
    def test02(self):
        print("test02執行")

案例

"""
    目標:unittest框架  - TestSuite使用
    操作:
        1. 導包
        2. 例項化獲取 TestSuite物件
        3. 呼叫addTest方法新增用例 到指定套件中
"""

# 導包
import unittest
from TestCase import Test01
from test_01 import Test02

# 例項化  suite
suite = unittest.TestSuite()

# 呼叫新增方法
# 寫法1   類名("方法名")
# 注意:方法名稱使用雙引號
suite.addTest(Test01("test_add"))
suite.addTest(Test01("test_add02"))

# 新增方法二
# 使用新增測試類中所有test開頭的方法
suite.addTest(unittest.makeSuite(Test02))

# 執行測試套件
runner = unittest.TextTestRunner()
runner.run(suite)

在這裡插入圖片描述

3)TestLoader【重點,推薦】

在這裡插入圖片描述

	說明:
		1. 將符合條件的測試方法新增到測試套件中
		2. 搜尋指定目錄檔案下指定字母開頭的模組檔案下test開始的方法,並將這些方法新增到測試套件中,最後返回測試套件
	操作: 
		1. 導包
				import unittest
		2. 呼叫TestLoader()
				寫法1. suite = unittest.TestLoader().discover("指定搜尋的目錄檔案","指定字母開頭模組檔案")
				寫法2. suite = unittest.defaultTestLoader.discover("指定搜尋的目錄檔案","指定字母開頭模組檔案") 【推薦】
				注意:如果使用寫法1,TestLoader()必須有括號。
		3. 執行測試套件
				unittest.TextTestRunner().run(suite)
"""
    目標:演示TestLoader()類的用法
    作用:搜尋指定目錄下指定開頭的py檔案,在Py檔案中搜尋test開頭測試方法,並且將這些方法新增到測試套件中,最後返回測試套件
    需求:
        執行 cases目錄下test01.py~test05.py檔案
    操作:
        1. 導包 unittest
        2. 呼叫TestLoader類下discaver方法
        3. 執行測試用例
"""
# 導包
import unittest
# 呼叫方法
# suite = unittest.TestLoader().discover("../cases")

# 擴充套件 指定 tpshop開頭的模組
# suite = unittest.TestLoader().discover("../cases", pattern="tpshop*.py")

# 擴充套件 使用 推薦使用
suite = unittest.defaultTestLoader.discover("../cases")

# 執行 套件 方法 TextTestRunner
unittest.TextTestRunner().run(suite)


在這裡插入圖片描述
在這裡插入圖片描述

(1)TestSuite與TestLoader的區別

共同點:都是測試套件
不同點:實現方式不同
		TestSuite: 要麼新增指定的測試類中所有test開頭的方法,要麼新增指定測試類中指定某個test開頭的方法
		TestLoader: 搜尋指定目錄下指定字母開頭的模組檔案中以test字母開頭的方法並將這些方法新增到測試套件中,最後返回測試套件

4)Fixture

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

說明:裝置函式(setUp、tearDown)
級別:
	1). 函式級別 def setUp() / def tearDown()
			特性:幾個測試函式,執行幾次。每個測試函式執行之前都會執行 setUp,執行之後都會執行tearDwon
	2). 類級別 def setUpClass() / def tearDownClass()
			特性:測試類執行之前執行一次setUpClass 類執行之後執行一次tearDownClass
			注意:類方法必須使用 @classmethod修飾
	3). 模組級別:def setUpModule() / def tearDownModule()
			特殊:模組執行之前執行一次setUpModule ,執行之後執行一次tearDownModule
			
提示:
	無論使用函式級別還是類級別,最後常用場景為:
		初始化:
			1. 獲取瀏覽器例項化物件
			2. 最大化瀏覽器
			3. 隱式等待
		結束:
			關閉瀏覽器驅動物件
import unittest
"""
    目標:unittest 中的fixture用法
    fixture其實就是兩個函式,這個函式可以一起使用,也可以單獨使用
        1. 初始化函式:def setUp()
        2. 結束函式: def tearDown()

    fixture級別:
        1. 函式級別 [常用]
        2. 類級別 [常用]
        3. 模組級別
"""
def setUpModule():
    print("setupModule")

def tearDownModule():
    print("tearDownModule")

class Test03(unittest.TestCase):
    # 修飾類方法的修飾器
    @classmethod
    def setUpClass(cls):
        print("setUpClass被執行")

    @classmethod
    def tearDownClass(cls):
        print("tearDownClass被執行")

    def setUp(self):
        print("setup被執行")

    def tearDown(self):
        print("tearDown被執行")



    def test01(self):
        print("test01被執行")

    def test02(self):
        print("test02被執行")


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

在這裡插入圖片描述

5)斷言

3.1 什麼是斷言?
	讓程式代替人為判斷執行結果是否與預期結果相等的過程
3.2 為什麼要斷言?
	自動化指令碼執行時都是無人值守,需要通過斷言來判斷自動化指令碼的執行是否通過
	注:自動化指令碼不寫斷言,相當於沒有執行測試一個效果。
3.3 常用斷言
	1. self.assertEqual(ex1, ex2)  #判斷ex1 是否相等ex2
	2. self.assertIn(ex1 ,ex2) # ex2是否包含ex1 注意:所謂的包含不能跳字元
	3. self.assertTrue(ex) # 判斷ex是否為True

在這裡插入圖片描述

import unittest

class Test04(unittest.TestCase):
    def test01(self):
        # 斷言是否為True
        print("test01被執行")
        flag = True
        self.assertTrue(flag)
        # self.assertFalse(flag)

    def test02(self):
        # 判斷兩個字串是否相等
        print("test02被執行")
        self.assertEqual("lin", "lin")

    def test03(self):
        # 判斷後邊的字串是否包含前邊的字串
        print("test03被執行")
        self.assertIn("lin","linzz")

    def test04(self):
        # 判斷是否為None
        print("test04被執行")
        flag = None
        self.assertIsNone(flag)
        # self.assertIsNotNone(flag)

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

在這裡插入圖片描述

(1)Tpshop案例

	目標:tpshop登入
	方法:
		def setUp():
			# 獲取driver
			# 開啟url
			# 最大化瀏覽器
			# 隱式等待
		def tearDown():
			# 關閉瀏覽器驅動
		
		def test_login_code_null():
			# 根據業務流程編寫
			# ...
			# 失敗截圖
"""
    目標:斷言練習
    案例:
        輸入:正確使用者名稱和密碼  驗證碼為空
        斷言:提示資訊是否為,驗證碼不能為空!
        要求:如果斷言出錯,截圖儲存。
"""
# 導包
import unittest
from selenium import webdriver
from time import sleep
from time import strftime
# 定義測試類   並繼承 unittest.TestCase
class TestTpshopLogin(unittest.TestCase):
    # 定義初始方法
    def setUp(self):
        # 獲取驅動物件
        self.driver = webdriver.Chrome()

        # 開啟url
        url = r"http://localhost"
        self.driver.get(url)

        # 最大化瀏覽器
        self.driver.maximize_window()

        # 隱式等待
        self.driver.implicitly_wait(10)

    # 定義結束方法
    def tearDown(self):
        sleep(5)
        self.driver.quit()

    # 定義登陸測試方法   驗證碼為空
    def test_login_code_null(self):
        driver = self.driver
        # 點選登陸連線
        driver.find_element_by_partial_link_text("登入").click()

        # 輸入使用者名稱
        driver.find_element_by_css_selector(
            "#username").send_keys("11111111111")
        
        # 輸入密碼
        driver.find_element_by_css_selector(
            "#password").send_keys("123456")

        # 輸入驗證碼
        driver.find_element_by_css_selector(
            "#verify_code").send_keys("")

        # 點選登陸
        driver.find_element_by_css_selector(
            ".J-login-submit").click()

        # 獲取登陸後提示資訊
        result = driver.find_element_by_css_selector(
            ".layui-layer-content").text
        print("result為:",result)

        # 定義預期結果
        expect_result = "驗證碼不能為空!!"

        try:
            # 斷言
            self.assertEqual(result,expect_result)

        except AssertionError:
            # 截圖
            driver.get_screenshot_as_file("./%s.png" % (strftime("%Y_%m_%d %H_%M_%S")))
            # 丟擲異常
            raise

6)引數化

4.1 為什麼要引數化
	解決冗餘程式碼問題;
4.2 什麼是引數化
	說明:根據需求動態獲取引數並引用的過程
4.3 引數化應用場景
	場景:解決相同業務邏輯,不同測試資料問題。
	
4.4 應用:
	1. 安裝外掛
		通過命令:
			安裝:
				pip install parameterized
			驗證:
				pip show parameterized
		通過pycharm:File-->setting-->Project 工程名稱
		
	2. 應用外掛
		1. 導包 from parameterized import parameterized
		2. 修飾測試函式 @parameterized.expand([資料])
			資料格式:
				1. 單個引數:型別為列表
				2. 多個引數:型別為列表巢狀元祖
				3. 在測試函式中的引數設定變數引用引數值,注意:變數的數量必須和資料值的個數相同
import unittest
from parameterized import parameterized

"""
    目標:parameterized 外掛應用
    步驟:
        1. 導包 from parameterized import parameterized
        2. 修飾測試函式 @parmeterized.expand(列表型別資料)
        3. 在測試函式中使用變數接收,傳遞過來的值。
        
    語法:
        1. 單個引數:值為列表
        2. 多個引數:值為列表巢狀元組 如:[(1,2,3),(2,3,4)]
"""


# 定義測試類 並 繼承
class Test01(unittest.TestCase):
    # 單個引數使用方法
    # @parameterized.expand(["1", "2", "3"])
    # def test_add_one(self, num):
    #     print("num:", num)

    # 多個引數使用方法 寫法1
    # @parameterized.expand([(1, 2, 3), (3, 0, 3), (2, 1, 3)])
    # def test_add_more(self, a, b, result):
    #     print("{}+{}={}:".format(a, b, result))

    # data = [(1, 2, 3), (3, 0, 3), (2, 1, 3)]
    # 寫法2
    # @parameterized.expand(data)
    # def test_add_more(self, a, b, result):
    #     print("{}+{}={}:".format(a, b, result))


    # 寫法 3 推薦
    def get_data(self):
        return [(1, 2, 3), (3, 0, 3), (2, 1, 3)]

    @parameterized.expand(get_data())
    def test_add_more(self, a, b, result):
        print("{}+{}={}:".format(a, b, result))

相關文章