python 和 selenium實現web UI功能自動化測試框架

以前分享了python和requests搭配實現的接口自動化測試框架,今天,我再來整理分析下基於python和selenium的web UI自動化測試,但願能對你們有所幫助,也是本身整理知識學習的方法,跟你們一塊兒努力,奮鬥在自動化測試的道路上。html

其實UI自動化和接口自動化框架的設計思路大同小異,主要目的仍是分離業務代碼和測試數據,達到代碼的複用,提升測試用例的可維護性以及最最重要的減小人工勞動力。那麼就開始直接看正文吧。python

設計目的:web

分離業務代碼和測試數據,提升代碼可維護性,實現自動化,減小重複勞動,最終達到「偷懶」的目的,哈哈哈哈哈~~ 哎呦,很差意思,一不當心暴露了真相。小編是真的在一本正經的寫代碼啦。chrome

框架目錄結構:api

        case:存放具體的測試代碼瀏覽器

        comm:存放共通的方法app

        file:存放測試用例等測試過程當中用到的測試數據框架

        result:每次測試的log和測試報告的存放位置學習

        caseList:規定執行哪些測試測試

        config:配置靜態數據

                                                                readConfig:讀取config文件內容

                                                                runAll:測試執行入口文件

一塊兒來看整個框架的搭建。

首先,要保證你的python已經安裝了selenium包,若是你是用pip來管理本身的python環境的,那麼你能夠經過下面的命令來導入selenium模塊:

pip install selenium

而後,你須要到網上去下載對應瀏覽器的驅動,這裏小編使用的是chrome瀏覽器,(chrome下載地址:http://chromedriver.storage.googleapis.com/index.html)。下載完成以後呢,將下載的瀏覽器驅動放到本地的python安裝目錄下,這樣就能夠直接在框架中使用了。至此,必備的條件都有了,咱們就能夠開工啦。

這裏呢,咱們就只挑部份內容進行講解,有許多跟接口測試框架相同或類似的方法和文件,就不一一進行二次說明了,第一次看的盆友們,有不明白的地方能夠看這篇文章,進行補充學習http://www.javashuo.com/article/p-koqjlcfy-ku.html

打開瀏覽器:

from selenium import webdriver

class Driver:

    def __init__(self):
        
        self.browser = webdriver.Chrome()

    def open_browser(self):
        """
        Do something for browser
        :return: browser
        """
        # 窗口最大化
        self.browser.maximize_window()

        # 打開地址連接
        url = 'http://www.baidu.com'
        self.browser.get(url)
        return self.browser

    def close_browser(self):
        """
        quit browser
        :return:
        """
        self.browser.quit()

從上面的代碼能夠看出,咱們進行了打開/關閉瀏覽器的方法定義,只有簡單的幾行代碼,固然了,這裏爲了方便你們觀看,我把url地址直接寫了出來,在實際操做時,咱們能夠將其抽離出來,根據本身的須要,傳入不一樣的url地址。這就留着讓你們去本身實現吧。

一個簡單的搜索栗子:

from time import sleep
from selenium import webdriver
import unittest


class Login(unittest.TestCase):

    def setUp(self):
        self.driver = webdriver.Chrome()

        # 窗口最大化
        self.driver.maximize_window()
        self.msg = '海賊王'
        self.url = 'http://www.baidu.com'

    def testSearch(self):
        """
        test body
        :return:
        """
        # open browser
        self.driver.get(self.url)
        sleep(3)
        # click search input
        self.driver.find_element_by_id('kw').click()
        sleep(1)

        # input value
        self.driver.find_element_by_id('kw').send_keys(self.msg)
        sleep(1)
        self.driver.find_element_by_id('su').click()
        sleep(1)

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

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

在上面的代碼裏,咱們在百度裏搜索了小編最愛的動漫,嘻嘻,是否是很開心啊,就這樣邊學邊玩耍,感受測試也是美美的。

selenium能夠經過不少種方式來定位元素。這個讀者能夠自行學習。

你們看到了,這就是UI測試的雛形,有了這個雛形,咱們就能夠對它進行擴展,擴展,最後搭出框架來。

添加log日誌:

在上面的基礎上,咱們能夠添加執行時輸出的log日誌。因此開始寫log文件,並將它放在comm文件夾下,做爲共同方法來用。這部份內容在接口測試框架那裏已經介紹過了,因此請還不清楚的朋友們移步此處:http://www.javashuo.com/article/p-koqjlcfy-ku.html

抽離出瀏覽器的相關操做:

咱們能夠將對瀏覽器的操做剝離出來,單獨放到一個文件中,這樣既清晰,又避免了重複的代碼操做。並且維護起來也比較方便。

from selenium import webdriver
from comm.Log import MyLog as Log
import readConfig
import threading

localReadConfig = readConfig.ReadConfig()


class Driver:

    def __init__(self):
        self.log = Log.get_log()
        self.logger = self.log.get_logger()

        self.browser = webdriver.Chrome()

    def open_browser(self, name1, name2):
        """
        Do something for browser
        :return: browser
        """
        self.logger.info("Open browser")

        # 窗口最大化
        self.browser.maximize_window()

        # 打開地址連接
        url = localReadConfig.get_webServer(name1, name2)
        self.browser.get(url)
        return self.browser

    def close_browser(self):
        """
        quit browser
        :return:
        """
        self.browser.quit()
        self.logger.info("Quit browser")

    def get_driver(self):
        """
        get web driver
        :return:
        """
        return self.browser


class MyDriver:

    driver = None
    mutex = threading.Lock()

    def __init__(self):
        pass

    @staticmethod
    def get_browser():

        if MyDriver.driver is None:
            MyDriver.mutex.acquire()
            MyDriver.driver = Driver()
            MyDriver.mutex.release()

        return MyDriver.driver

if __name__ == "__main__":
    driver = MyDriver.browser()
    browser = driver.open_browser()

以上即是小編剝離出來的部分,而且將它放到了單獨的線程中。

有木有以爲眼熟呢?其實就跟log的原理是同樣的啦。這就是「觸類旁通」哦,套路就是那個套路,就看你怎麼用了。

關於Element的那些事兒:

作過UI功能測試的朋友們應該都知道,元素是咱們測試最基本也是最重要的東西,覺得它是咱們直接的操做對象,因此,處理好它們,咱們就會省掉不少的麻煩,因此呢,接下來,小編將會繼續分享本身處理element的一些方法,但願能對你們有所幫助,若是哪位大神有更好的方法,請必定要告訴小編哦!小編在此先謝過了!

class Element:

    def __init__(self, activity_name, element_name):

        self.driver1 = Driver.get_browser()
        self.driver = self.driver1.get_driver()
        self.activity = activity_name
        self.element = element_name
        element_dict = get_el_dict(self.activity, self.element)
        self.pathType = element_dict.get('pathType')
        self.pathValue = element_dict.get('pathValue')

    def is_exist(self):
        """
        Determine element is exist
        :return: TRUE OR FALSE
        """
        try:
            if self.pathType == 'ID':
                self.driver.find_element_by_id(self.pathValue)
                return True
            if self.pathType == 'XPATH':
                self.driver.find_elements_by_xpath(self.pathValue)
                return True
            if self.pathType == 'CLASSNAME':
                self.driver.find_element_by_class_name(self.pathValue)
                return True
            if self.pathType == 'NAME':
                self.driver.find_element_by_name(self.pathValue)
                return True
        except NoSuchElementException:
            return False

    def wait_element(self, wait_time):
        """
        wait element appear in time
        :param wait_time: wait time
        :return: true or false
        """
        time.sleep(wait_time)
        if self.is_exist():
            return True
        else:
            return False

    def get_element(self):
        """
        get element
        :return: element
        """
        try:
            if self.pathType == 'ID':
                element = self.driver.find_element_by_id(self.pathValue)
                return element
            if self.pathType == 'XPATH':
                element = self.driver.find_elements_by_xpath(self.pathValue)
                return element
            if self.pathType == 'CLASSNAME':
                element = self.driver.find_element_by_class_name(self.pathValue)
                return element
            if self.pathType == 'NAME':
                element = self.driver.find_element_by_name(self.pathValue)
                return element
        except NoSuchElementException:
            return None

    def get_element_by_index(self, index):
        """
        get element by index
        :param index: index
        :return: element
        """
        try:
            if self.pathType == 'ID':
                element = self.driver.find_element_by_id(self.pathValue)
                return element[index]
            if self.pathType == 'XPATH':
                element = self.driver.find_elements_by_xpath(self.pathValue)
                return element[index]
            if self.pathType == 'CLASSNAME':
                element = self.driver.find_element_by_class_name(self.pathValue)
                return element[index]
            if self.pathType == 'NAME':
                element = self.driver.find_element_by_name(self.pathValue)
                return element[index]
        except NoSuchElementException:
            return None

    def get_element_list(self):
        """
        get element list
        :return: element list
        """
        try:
            if self.pathType == 'ID':
                element_list = self.driver.find_element_by_id(self.pathValue)
                return element_list
            if self.pathType == 'XPATH':
                element_list = self.driver.find_elements_by_xpath(self.pathValue)
                return element_list
            if self.pathType == 'CLASSNAME':
                element_list = self.driver.find_element_by_class_name(self.pathValue)
                return element_list
            if self.pathType == 'NAME':
                element_list = self.driver.find_element_by_name(self.pathValue)
                return element_list
        except NoSuchElementException:
            return None

    def click(self):
        """
        click element
        :return:
        """
        element = self.get_element()
        time.sleep(1)
        element.click()

    def send_key(self, key):
        """
        input key
        :param key: input value
        :return:
        """
        element = self.get_element()
        time.sleep(1)
        element.clear()
        element.send_keys(key)

    def input_keys(self, index, key):
        """
        By index send key
        :param index: index
        :param key: key
        :return:
        """
        element = self.get_element_by_index(index)
        time.sleep(1)
        element.clear()
        element.send_keys(key)

    def get_text_value(self):
        """
        get attribute
        :return:
        """
        element = self.get_element()
        value = element.get_attribute('text')
        return str(value)

這是小編寫的,目前能用到的關於element的方法了,累覺不愛啊~

可是,生活還要繼續,工做還未完成。因此,請讓我講完剩下的代碼吧!!!

那些讓人費神的測試數據文件:

每個好的測試,都離不開一份好的測試用例數據,那麼,這麼多的數據,咱們要怎樣進行管理才能既不亂又方便之後對數據進行更改維護呢?下面,小編就要告訴朋友們一個重磅消息,敲黑板!!!

其實,小編也不知道有什麼好辦法,小編就是使用excel文件來對測試用例進行統一管理的。請看下面:

形式就是這麼個形式,內容就隨便大家怎麼修改了。畢竟我也只能幫大家到這裏了。至於對excel文件內容的讀取,在接口測試那篇博文中也有詳細介紹哦。不明白的同窗請移步:http://www.javashuo.com/article/p-koqjlcfy-ku.html

其實,出來測試用例,還有一個數量龐大的數據羣體,快猜猜它們是誰???

噹噹噹,答案就是:元素定位的數據,包括:id,name,classname,xpath等等,這些數據但是咱們在測試過程當中找到頁面元素的不二法門哦。。。因此各位朋友必定要注意啦,必定要處理好它們。

請看下面:

愚蠢的小編就用xml文件來管理啦。

是否是又有人想問怎麼讀取xml文件了?嘿嘿。。。我不會告訴你的,由於我在前面的博文裏已經講過啦!講過啦!過啦!啦!!

至此呢,今天的內容也結束了,但願對你們有所啓發和幫助,雖然講的有些凌亂,不過只要弄懂了這些劃分和實現方法,我相信,你也必定能夠寫出本身滿意的UI自動化測試框架。因此,咱們一塊兒加油吧。

PS:有些沒有提到的部分,因爲跟以前介紹接口自動化框架的內容同樣,因此就再也不累述,有想了解的朋友,移步此處便可。謝謝!http://www.javashuo.com/article/p-koqjlcfy-ku.html

 

本文爲原創文章,轉載請註明原文地址,謝謝你們的支持。但願你們一塊兒努力成長。

相關文章
相關標籤/搜索