Try/Except的一點心得(selenium斷言和元素操作處理)

寫在前面的:
最近在學習寫UI自動化腳本钮呀,并且正在自己的項目中實踐删掀。
在斷言的時候使用了try語句塊患膛,其實自己只是對python對try語句有基本的語法認識凡蚜,根本不知道怎么去用人断。結果出了個bug,老半天才找出原因來朝蜘。是因為自己把好多代碼都try了恶迈,結果有錯誤也沒曝露出來,很是憂桑芹务。當時有點懷疑人生了蝉绷,為什么沒報錯,但是卻沒有得到自己預想的結果呢枣抱?
有問題的代碼類似下面這樣(當時的代碼找不到了熔吗,下面代碼只是說明下錯誤):

#coding=utf-8
def div(a,b):
        try:
            result=a/b
            return result
        except Exception as e:
            print("不知道發(fā)生了什么。佳晶。")

if __name__=="__main__":
    print(div(1,0))

第一個禁忌:避免捕捉所有異常并吞噬它們桅狠。
看上去好像在處理異常的時候也打印了一句“不知道發(fā)生了什么”,但其實這里是把0作為除數(shù)的這種錯誤給吞噬了轿秧,也就是說中跌,代碼沒有對這種錯誤情況給出一個原因或者針對性對解決方案。
這種情況的解決辦法:

def div1(a,b):
    """
    :param a: int或者float類型
    :param b: int或者float類型
    :return: 如果a菇篡,b不是int或者foat類型漩符,返回None;如果b=0,返回None;否則返回a/b的結果
    """

    if not isinstance(a,(int,float)) :
        return None
    if not isinstance(b,(int,float)):
        return None
    if 0==b:
        return None
    result=a/b
    return result

這種方法就是對于一個傳進來的參數(shù)做這種校驗驱还,因為你不知道別人會傳什么樣的參數(shù)嗜暴,所以要想到各種情況。
如果有的時候议蟆,代碼中很多地方都可能會發(fā)生異常闷沥,類型可預見,但是什么時候發(fā)生不知道咐容,這就要用TryExcept語句舆逃。比如webdriver的元素操作,有時候是元素的獲取有問題戳粒,有時候是操作元素的時候有問題路狮,常見都就是報錯ElementNotVisibleException、NoSuchElementException蔚约,還有一些其他的異常(如下圖)览祖。


image.png

你在做頁面操作的時候可能是一系列操作,那每個元素都要判斷是否正常返回嘛炊琉?那估計是要累死寶寶了展蒂。這時候用TryExcept就很方便。我是這樣處理的:
1.所有元素獲取和操作的部分try
2.如果except到了異常苔咪,根據異常的種類做不同的處理锰悼。ElementNotVisibleException、NoSuchElementException這兩種異常是我最常遇見的团赏,原因就是腳本不太穩(wěn)定箕般,大多數(shù)情況下是可以通過用例的,少數(shù)情況會報這兩個異常舔清,那么我希望遇到這兩種異常的時候重新跑用例腳本丝里,代碼不會因此而中斷曲初,增強了代碼的健壯性。遇到未知的Exception杯聚,此時一定要raise出來臼婆,raise之前也可以自己打點日志。
3.對于webdriver的assert方法也要try一下幌绍。因為assert方法只要失敗颁褂,就會拋AssertionError(感覺這種處理方式不是很好,但是又必須用selenium傀广,通常情況應該是正確或者錯誤都需要返回一個值颁独,而不是拋出一個異常呀)。except語句塊主要是記錄下測試用例失敗的數(shù)據伪冰,然后也要raise掉誓酒。如果不raise掉,那么這個用例結果會是成功(但實際是失敗了贮聂,只不過你但try讓它看起來成功了)丰捷。代碼如下:

    def testToolButton(self):
        logger.info("開始執(zhí)行工具按鈕的測試腳本...")
        try:
            # 設置瀏覽器為iphone模式打開
            mobile_emulation = {'deviceName': 'Galaxy S5'}
            options = webdriver.ChromeOptions()
            options.add_experimental_option("mobileEmulation", mobile_emulation)
            browser = webdriver.Chrome(chrome_options=options)
            browser.get("https://plogin.m.jd.com/user/login.action")
            logger.info('啟動瀏覽器,訪問"登錄"頁面...')
            LoginAction.login('13180314708','TGB6yhn',browser,'http://test-jdread.jd.com/h5/m/')
            logger.info('登錄完成...')
            time.sleep(3)
            logger.info('創(chuàng)建書城頁面寂汇,點擊工具按鈕病往,點擊"我的"按鈕...')
            bookCityPage = BookCityPage(browser)
            bookCityPage.toolButtonObj().click()
            bookCityPage.minePageButtonObj().click()
            time.sleep(3)
            minePage=MinePage(browser)
            try:
                minePage.ExitButtonObj()#如果在"我的"頁面找到退出按鈕,則通過測試用例骄瓣,如果沒找到該按鈕則測試用例未通過
                self.assertTrue(1==1)
                logger.info('在"我的"頁面找【退出】按鈕停巷,成功,用例通過')
            except AssertionError as e:
                logger.debug('在"我的"頁面找到【退出】按鈕榕栏,失敗畔勤,用例不通過')
                raise e

        except ElementNotVisibleException as e:

            logger.error("元素不可見..")

        except NoSuchElementException as e:

            logger.error("元素沒有找到..")

        except Exception as e:

            logger.error(e)

            raise e

另外python允許程序員自己寫一些異常類,這時候要注意的就是禁忌二:拋出的異常應該解釋為什么扒磁,不能讓別人來猜測庆揪,你可能注意到,selenium定義類很多異常妨托,但是人家還是把異常信息的原因返回的很清楚缸榛。同理,我們自己在寫異常的時候兰伤,拋出時也要寫清楚為什么内颗,方便別人在用的時候不知道發(fā)生了什么就拋出了異常。以下代碼是一個自己定義異常的例子敦腔,ShortInputException類里面有兩個成員變量length和atleast均澳,分別代表輸入的長度和要求最短的長度,一旦length小于atleast就應該拋出異常。這兩個成員變量就能說明異常的原因:

#coding=utf-8
import sys
class ShortInputException(Exception):
    def __init__(self,length,atleast):
        Exception.__init__(self)
        self.length=length
        self.atleast=atleast

def assertInputLength(atleastLen):
        s=input("請輸入一個長度大于%s的字符串:"%str(atleastLen))
        if len(s)<atleastLen:
            raise ShortInputException(len(s),atleastLen)
        else:
            return True
try:
    assertInputLength(3)
except ShortInputException as e:
    sys.stderr.write("%s is not enough long ,atleast %s \n"%(e.length,e.atleast))

禁忌三:不要使用異常來控制進程找前,這樣您的程序就很難理解和維護
雖然python是一種很“自由”的語言糟袁,tryExcept能做很多事情,筆者自己就寫過這樣的代碼:

#coding=utf-8
import time

def AIclick(element):
    for i in range(60):  # 循環(huán)60次躺盛,從0至59
        if i >= 59:  # 當i大于等于59時项戴,打印提示時間超時
            print("timeout")
            break
        try:  # try代碼塊中出現(xiàn)找不到特定元素的異常會執(zhí)行except中的代碼
            element.click()
        except:  # 上面try代碼塊中出現(xiàn)異常,except中的代碼會執(zhí)行打印提示會繼續(xù)嘗試查找特定的元素id
            print("wait for find element")
        else:
            break
        time.sleep(1)

以上代碼是為了穩(wěn)定的獲取頁面元素颗品。但不得不說肯尺,這樣的代碼很難讓人理解沃缘。代碼邏輯簡單還好躯枢,一旦復雜,就會跳進自己挖的坑里槐臀。

禁忌四:如果有需要锄蹂,記得使用最后釋放資源
這里使用java來說明下,最有名的就是數(shù)據庫的操作:

package com.runoob.test;
 
import java.sql.*;
 
public class MySQLDemo {
 
    // MySQL 8.0 以下版本 - JDBC 驅動名及數(shù)據庫 URL
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";  
    static final String DB_URL = "jdbc:mysql://localhost:3306/RUNOOB";
 
    // MySQL 8.0 以上版本 - JDBC 驅動名及數(shù)據庫 URL
    //static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";  
    //static final String DB_URL = "jdbc:mysql://localhost:3306/RUNOOB?useSSL=false&serverTimezone=UTC";
 
 
    // 數(shù)據庫的用戶名與密碼水慨,需要根據自己的設置
    static final String USER = "root";
    static final String PASS = "123456";
 
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        try{
            // 注冊 JDBC 驅動
            Class.forName(JDBC_DRIVER);
        
            // 打開鏈接
            System.out.println("連接數(shù)據庫...");
            conn = DriverManager.getConnection(DB_URL,USER,PASS);
        
            // 執(zhí)行查詢
            System.out.println(" 實例化Statement對象...");
            stmt = conn.createStatement();
            String sql;
            sql = "SELECT id, name, url FROM websites";
            ResultSet rs = stmt.executeQuery(sql);
        
            // 展開結果集數(shù)據庫
            while(rs.next()){
                // 通過字段檢索
                int id  = rs.getInt("id");
                String name = rs.getString("name");
                String url = rs.getString("url");
    
                // 輸出數(shù)據
                System.out.print("ID: " + id);
                System.out.print(", 站點名稱: " + name);
                System.out.print(", 站點 URL: " + url);
                System.out.print("\n");
            }
            // 完成后關閉
            rs.close();
            stmt.close();
            conn.close();
        }catch(SQLException se){
            // 處理 JDBC 錯誤
            se.printStackTrace();
        }catch(Exception e){
            // 處理 Class.forName 錯誤
            e.printStackTrace();
        }finally{
            // 關閉資源
            try{
                if(stmt!=null) stmt.close();
            }catch(SQLException se2){
            }// 什么都不做
            try{
                if(conn!=null) conn.close();
            }catch(SQLException se){
                se.printStackTrace();
            }
        }
        System.out.println("Goodbye!");
    }
}

禁忌五:處理異常后不要忘記清理或回滾
這里還是用java的數(shù)據庫事務操作來說明下:

public boolean DeleteSeatInfo(Seat seat){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        String sql="UPDATE info_seat seat,info_classroom room SET seat.seat_student_name = ? ,seat.seat_empty = ? WHERE seat.classroom_id = room.classroom_id AND seat_id = ?";
        try{
            conn = DbUtils.getConnection();
            conn.setAutoCommit(false);
            ps = conn.prepareStatement(sql);
            System.out.println(sql);
            ps.setString(1,seat.getSeatName());
            ps.setInt(2, seat.getIsEmpty());
            ps.setString(3, seat.getSeatId());
            //ps.addBatch();
            //ps.executeBatch(); //批量執(zhí)行 
            ps.executeUpdate();
            conn.commit();//提交事務  
            return true;

        }catch(SQLException e){
             try {  
                 conn.rollback(); //進行事務回滾  
             } catch (SQLException ex) {   
             }
        }finally {
            DbUtils.close(conn, ps, rs);
        }
        return false;
    }

文章參考以下大牛的:
http://news.51cto.com/art/201801/565741.htm
https://www.cnblogs.com/cnkemi/p/8985654.html
http://www.runoob.com/java/java-mysql-connect.html
https://blog.csdn.net/yy763496668/article/details/51488882

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末得糜,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子晰洒,更是在濱河造成了極大的恐慌朝抖,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谍珊,死亡現(xiàn)場離奇詭異治宣,居然都是意外死亡,警方通過查閱死者的電腦和手機砌滞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門侮邀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贝润,你說我怎么就攤上這事绊茧。” “怎么了打掘?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵华畏,是天一觀的道長。 經常有香客問我尊蚁,道長唯绍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任枝誊,我火速辦了婚禮况芒,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己绝骚,他們只是感情好耐版,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著压汪,像睡著了一般粪牲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上止剖,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天腺阳,我揣著相機與錄音,去河邊找鬼穿香。 笑死亭引,一個胖子當著我的面吹牛,可吹牛的內容都是我干的皮获。 我是一名探鬼主播焙蚓,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼洒宝!你這毒婦竟也來了购公?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤雁歌,失蹤者是張志新(化名)和其女友劉穎宏浩,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體靠瞎,經...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡比庄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了较坛。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片印蔗。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖丑勤,靈堂內的尸體忽然破棺而出华嘹,到底是詐尸還是另有隱情,我是刑警寧澤法竞,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布耙厚,位于F島的核電站,受9級特大地震影響岔霸,放射性物質發(fā)生泄漏薛躬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一呆细、第九天 我趴在偏房一處隱蔽的房頂上張望型宝。 院中可真熱鬧,春花似錦、人聲如沸趴酣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽岖寞。三九已至抡四,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間仗谆,已是汗流浹背指巡。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留隶垮,地道東北人藻雪。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像岁疼,于是被迫代替她去往敵國和親阔涉。 傳聞我的和親對象是個殘疾皇子缆娃,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355