【selenium】python+selenium+unittest,關於每次執行完一個測試用例都關閉瀏覽器等時間較長的問題之解決方案


 我一直在思考第一個博客應該寫什么,然后我就解決了開通博客后解決的第一個問題,擇題不如撞題;

  如果大多數人和我一樣,接觸python+selenium+unittest是從selenium IDE開始的話,你也一定會遇到這樣的問題:

  我們寫了5個,10個,甚至20個測試用例,放在一個py腳本里,每個測試用例執行完畢之后,都會走一遍退出瀏覽器的操作,然后再啟動瀏覽器,再退出,如此反復,浪費了大量的時間,今天就說說我研究解決這個問題的歷程;

  我們第一個錄制並導出的python selenium代碼,萬能的“登錄功能”,是這個樣子的:

# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re

class Login(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.base_url = "http://192.168.1.207:8080"
        self.verificationErrors = []
        self.accept_next_alert = True

    def test_login(self):
        driver = self.driver
        driver.get(self.base_url + "/QAS/RchWebSchool/")
        driver.find_element_by_css_selector("span").click()
        driver.find_element_by_name("j_password").clear()
        driver.find_element_by_name("j_password").send_keys("admin")
        driver.find_element_by_name("j_username").clear()
        driver.find_element_by_name("j_username").send_keys("admin")
        driver.find_element_by_xpath("//button[@type='submit']").click()

    def is_element_present(self, how, what):
        try: self.driver.find_element(by=how, value=what)
        except NoSuchElementException as e: return False
        return True

    def is_alert_present(self):
        try: self.driver.switch_to_alert()
        except NoAlertPresentException as e: return False
        return True

    def close_alert_and_get_its_text(self):
        try:
            alert = self.driver.switch_to_alert()
            alert_text = alert.text
            if self.accept_next_alert:
                alert.accept()
            else:
                alert.dismiss()
            return alert_text
        finally: self.accept_next_alert = True

    def tearDown(self):
        self.driver.quit()
        self.assertEqual([], self.verificationErrors)

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

  往往我們很容易讀懂這三個def(如果讀不懂,請看蟲師先生的博客:selenium-webdriver(python) (十六) --unittest 框架):

    setUp(self)
    test_login(self)
    tearDown(self)

  讀懂之后,我們就可以寫另外一個功能“修改個人信息”的自動化腳本了,假設我們在class:Login 里是這樣寫的:

    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(30)
        self.base_url = "http://192.168.1.207:8080"
        self.verificationErrors = []
        self.accept_next_alert = True

    def test_login(self):
        driver = self.driver
        driver.get(self.base_url + "/QAS/RchWebSchool/")
        driver.find_element_by_css_selector("span").click()
        driver.find_element_by_name("j_password").clear()
        driver.find_element_by_name("j_password").send_keys("admin")
        driver.find_element_by_name("j_username").clear()
        driver.find_element_by_name("j_username").send_keys("admin")
        driver.find_element_by_xpath("//button[@type='submit']").click()
    
    def test_login_reg(self):
        driver = self.driver
        driver.get(self.base_url + "/QAS/RchWebSchool/")

        #登錄代碼
        ...
        #修改個人信息代碼
        ...


    def tearDown(self):
        self.driver.quit()
        self.assertEqual([], self.verificationErrors)

  我們發現,每增加一個測試用例,都增加一次操作:啟動瀏覽器(setUp)→登錄測試網址(#登錄代碼)→關閉瀏覽器(teardown),而當用例過多的時候,如此反復的操作會浪費大量的時間;

  怎么辦呢?  

  如果我們能只走一次啟動瀏覽器和退出瀏覽器,那該有多好啊;

  我們嘗試將所有的功能的操作都寫在一個test里面,我們的test_login(self)代碼就變成了這樣:

    def test_login(self):
        driver = self.driver
        driver.get(self.base_url + "/QAS/RchWebSchool/")
        driver.find_element_by_css_selector("span").click()
        driver.find_element_by_name("j_password").clear()
        driver.find_element_by_name("j_password").send_keys("admin")
        driver.find_element_by_name("j_username").clear()
        driver.find_element_by_name("j_username").send_keys("admin")
        driver.find_element_by_xpath("//button[@type='submit']").click()
        
        
        #修改個人信息
        ...
        #功能續3
        ...
        #功能續4
        ...

  但是,這樣就了一個新的問題,當我們只測試其中一個功能,或者用到其中某一個功能的時候,沒有辦法單獨調用某一個功能的代碼,失去了原本的靈活性;

  所以陽陽針對class:Login里的代碼進行這樣改(請看注釋):

 1     dr = webdriver.Firefox()#定義全局的dr,不在setUp函數里,實現了只啟動一次firefox
 2     def setUp(self,driver= dr):
 3         self.driver = driver#初始化數據中,將全局變量dr賦值給self.driver,這樣每次測試開始都只會鎖定dr,而不是新創建一個
 4         self.driver.implicitly_wait(30)
 5         self.base_url = "http://192.168.1.207:8081"
 6         self.verificationErrors = []
 7         self.accept_next_alert = True
 8 
 9     def test_login(self):
10         driver = self.driver
11         driver.get(self.base_url + "/RchWebSchool/")
12         driver.find_element_by_css_selector("span").click()
13         driver.find_element_by_name("j_password").clear()
14         driver.find_element_by_name("j_password").send_keys("admin")
15         driver.find_element_by_name("j_username").clear()
16         driver.find_element_by_name("j_username").send_keys("admin")
17         driver.find_element_by_xpath("//button[@type='submit']").click()
18 
19     def test_login_reg(self):
20         driver = self.driver
21         #driver.get(self.base_url + "/RchWebSchool/")
22         ...
23         #修改個人信息自動化代碼
24         ...
25 
26     def test_zzz_quit(self):#最后一個測試用例,實現了只進行一次退出瀏覽器
27         self.driver.quit()
28 
29 
30     def tearDown(self):
31         try:
32             self.driver.refresh()#將退出瀏覽器的操作變成刷新瀏覽器,用於不同用例之間的接洽操作
33         except ConnectionRefusedError as e:
34             print(e)
35         finally:
36             self.assertEqual([], self.verificationErrors)

  大家應該看到,陽陽把tearown(self)里面的代碼已經改的面目全非了,這是因為我們每個測試用例(test_xxx)執行之后,都會走一次tearown,最后一個退出瀏覽器的test_zzz_quit當然也不例外,所以在走完test_zzz_quit之后,一定會再次執行刷新瀏覽器的操作,但是此前瀏覽器已經被關閉了,刷新瀏覽器一定會報錯,所以把異常ConnectionRefusedError拋出,不再進行處理,視為測試用例通過;

  當然,如果自動化只到這里的話,大家也可把teardown干掉,把每次刷新瀏覽器的操作放在每個測試用例的最后面,都是可以的,我只是習慣性保持unittest的完整性;

  


免責聲明!

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



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