內部UI自動化測試培訓之unittest基礎

image

這個文檔的由來是公司內部UI自動化測試培訓的資料。部門爲了減少測試工作量,準備做UI自動化測試。我寫python,其他同事都是java,所以python基礎和UI自動化測試selenium的培訓就由我來完成。本篇是單元測試工具uniitest的基礎介紹。

UI 自動化測試相關內容:

unittest 介紹

Unittest是Python內部自帶的一個單元測試的模塊,它設計的靈感來源於Junit,具有和Junit類似的結構,有過Junit經驗的朋友可以很快上手。它可以做單元測試, 也能用於編寫和運行重複的測試工作。
它給自動化測試用例開發和執行提供了豐富的斷言方法, 判斷測試用例是否通過, 並最終生成測試結果。

TestCase 測試用例編寫

unittest 基本知識包括如下:

  • TestCase指的就是測試用例
  • 測試類必須繼承unittest.TestCase
  • 測試方法名稱命名必須以test開頭
  • 測試方法的執行順序由Case序號決定, 並非由代碼順序決定
# 1. 導入unittest
import unittest

# 2. 創建類繼承unittest.TestCase
class TestDemo(unittest.TestCase):
    # 3. 創建測試用例方法, 方法要以test開頭
    # 執行順序是根據case序號來的, 並非代碼的順序
    def test_add_01(self):
        print(3+2)
        assert 3+2 == 5

    def test_add_02(self):
        print(5+5)
        assert 5+5 == 10


if __name__ == '__main__':
    unittest.main()
(dev) ➜  ui_test python unittest_demo.py
5
.10
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

unittest 特性

unittest 測試類中有一些特殊方法可以方便單元測試的環境準備和結束收尾,下面分別介紹。

單個測試用例

一個測試用例就是類似中的一個方法,啓動一個測試用例可能需要準備參數,準備環境。以下兩個方法可以用於當前場景:

  • setUp 初始化測試環境, 它在每條測試用例執行前都會調用
  • tearDown 測試用例執行完畢後恢復測試環境, 即使出現異常也會調用此方法,每條用例執行結束後都會運行
import unittest

class Test(unittest.TestCase):
    def setUp(self) -> None:  # 調用setUp
        super().setUp()
        print("測試用例執行前操作")

    def test_add_01(self):
        print("num02")

    def test_add_02(self):
        print("num03")

    def tearDown(self) -> None:  # 調用tearDown
        super().tearDown()
        print("測試用例執行後操作")


if __name__ == '__main__':
    unittest.main()
(idt_dev) ➜  ui_auto_test python unittest_demo.py
測試用例執行前操作
num02
測試用例執行後操作
.測試用例執行前操作
num03
測試用例執行後操作
.
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

setUp 和 tearDown 會在每一個測試用例執行時生效,setUp在用例執行前執行,tearDown在用戶執行後執行。

全局測試用例

在所有測試用例執行前可能也會需要一些初始化工作,如果能完成就可以避免在單個用例中重複工作。而 setUpClass 和 tearDownClass 可以完成相關工作。

  • setUpClass 初始化測試環境且只會執行一次。在類中需要加上@classmethod
  • tearDownClass 恢復測試環境且只會執行一次。在類中需要加上@classmethod
import unittest


class Test(unittest.TestCase):
    @classmethod
    def setUpClass(cls) -> None:
        super().setUpClass()
        print("測試前的操作")

    @classmethod
    def tearDownClass(cls) -> None:
        super().tearDownClass()
        print("測試後的操作")

    def test_add_01(self):
        print("num01")

    def test_add_02(self):
        print("num02")


if __name__ == '__main__':
    unittest.main()
測試前的操作
num01
.num02
.測試後的操作

----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

在所有測試用例之前會執行setUpClass,而且只會執行一次。所有測試用例執行完成之後執行tearDownClass,同樣只會執行一次。
斷言表達式
斷言表達式用於檢測一個變量是否符合預期,常見的斷言表達式如下:

斷言表達式

示例如下:

import unittest


class Test(unittest.TestCase):
    def setUp(self) -> None:
        super().setUp()
        print("測試開始")

    def test_add_01(self):
        print("1 == 1")
        self.assertEqual(1, 1)  # 成功

    def test_add_02(self):
        print("1 == 2")
        self.assertEqual(1, 2)  # 失敗

    def test_add_03(self):
        print("x is True")
        self.assertTrue(True)  # 成功

    def test_add_04(self):
        print("x is False")
        self.assertFalse(False)  # 失敗

    def test_add_05(self):
        print("a in b")
        self.assertIn(1, [1,2,3])  # 成功

    def test_add_06(self):
        print("a not in b")
        self.assertNotIn(1, [1,2,3])  # 失敗

    def tearDown(self) -> None:
        super().tearDown()
        print("測試結束")


if __name__ == '__main__':
    unittest.main()
測試開始
1 == 1
測試結束
.測試開始
1 == 2
測試結束
F測試開始
x is True
測試結束
.測試開始
x is False
測試結束
.測試開始
a in b
測試結束
.測試開始
a not in b
測試結束
F
======================================================================
FAIL: test_add_02 (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "unittest_demo.py", line 15, in test_add_02
    self.assertEqual(1, 2)  # 失敗
AssertionError: 1 != 2

======================================================================
FAIL: test_add_06 (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "unittest_demo.py", line 31, in test_add_06
    self.assertNotIn(1, [1,2,3])  # 失敗
AssertionError: 1 unexpectedly found in [1, 2, 3]

----------------------------------------------------------------------
Ran 6 tests in 0.000s

FAILED (failures=2)

測試工程

單元測試是一個工程,由多個python文件組成的,工程的代碼組織應該有一個清晰的規範。規範如下:

  1. 創建一個包保存所有的文件
  2. 一個主入口執行所有單元測試
    結構如下:

test_1.py

import unittest


class Test(unittest.TestCase):
    def setUp(self) -> None:
        super().setUp()
        print("測試開始")

    def test_add_01(self):
        print("1 == 1")
        self.assertEqual(1, 1)  

    def test_add_02(self):
        print("1 == 2")
        self.assertEqual(1, 2) 

    def tearDown(self) -> None:
        super().tearDown()
        print("測試結束")

test_2.py

import unittest


class Test(unittest.TestCase):
    def setUp(self) -> None:
        super().setUp()
        print("測試開始")

    def test_add_03(self):
        print("x is True")
        self.assertTrue(True)

    def test_add_04(self):
        print("x is False")
        self.assertFalse(False)

    def tearDown(self) -> None:
        super().tearDown()
        print("測試結束")

test_main.py

import unittest

# dicsover方法查找用例
suite = unittest.defaultTestLoader.discover("unittest_demo", "test*.py")

# 2.TextTestRunner運行用例
runer = unittest.TextTestRunner()

runer.run(suite)

運行結果:

測試開始
1 == 1
測試結束
.測試開始
1 == 2
測試結束
F測試開始
x is True
測試結束
.測試開始
x is False
測試結束
.
======================================================================
FAIL: test_add_02 (test_1.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/ljk/Documents/code/python-dev/ui_auto_test/unittest_demo/test_1.py", line 15, in test_add_02
    self.assertEqual(1, 2) 
AssertionError: 1 != 2

----------------------------------------------------------------------
Ran 4 tests in 0.000s

FAILED (failures=1)

selenium + unittest 完整示例

import time
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By

class MyTestCase(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Chrome()  # 初始化瀏覽器驅動

    def test_baidu_search(self):

        # 打開百度首頁
        self.driver.get("https://www.baidu.com")

        # 斷言頁面標題是否包含"百度一下"
        self.assertIn("百度一下", self.driver.title)

        # 找到搜索框並填充內容
        search_input = self.driver.find_element(By.NAME, "wd")
        search_query = "python selenium"
        search_input.send_keys(search_query)

        time.sleep(6)
        search_input.submit()

        self.driver.implicitly_wait(5)

        # 定位搜索結果元素
        search_results = self.driver.find_elements(By.CSS_SELECTOR, ".result.c-container")
        for result in search_results:
            print(result.text)

        # 斷言搜索結果是否顯示
        self.assertTrue(search_results)

    def tearDown(self):
        self.driver.quit()  # 關閉瀏覽器驅動

if __name__ == '__main__':
    unittest.main()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章