美文网首页
Try/Except的一点心得(selenium断言和元素操作处

Try/Except的一点心得(selenium断言和元素操作处

作者: Judy警官 | 来源:发表于2019-06-28 14:06 被阅读0次

写在前面的:
最近在学习写UI自动化脚本,并且正在自己的项目中实践。
在断言的时候使用了try语句块,其实自己只是对python对try语句有基本的语法认识,根本不知道怎么去用。结果出了个bug,老半天才找出原因来。是因为自己把好多代码都try了,结果有错误也没曝露出来,很是忧桑。当时有点怀疑人生了,为什么没报错,但是却没有得到自己预想的结果呢?
有问题的代码类似下面这样(当时的代码找不到了,下面代码只是说明下错误):

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

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

第一个禁忌:避免捕捉所有异常并吞噬它们。
看上去好像在处理异常的时候也打印了一句“不知道发生了什么”,但其实这里是把0作为除数的这种错误给吞噬了,也就是说,代码没有对这种错误情况给出一个原因或者针对性对解决方案。
这种情况的解决办法:

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

这种方法就是对于一个传进来的参数做这种校验,因为你不知道别人会传什么样的参数,所以要想到各种情况。
如果有的时候,代码中很多地方都可能会发生异常,类型可预见,但是什么时候发生不知道,这就要用TryExcept语句。比如webdriver的元素操作,有时候是元素的获取有问题,有时候是操作元素的时候有问题,常见都就是报错ElementNotVisibleException、NoSuchElementException,还有一些其他的异常(如下图)。


image.png

你在做页面操作的时候可能是一系列操作,那每个元素都要判断是否正常返回嘛?那估计是要累死宝宝了。这时候用TryExcept就很方便。我是这样处理的:
1.所有元素获取和操作的部分try
2.如果except到了异常,根据异常的种类做不同的处理。ElementNotVisibleException、NoSuchElementException这两种异常是我最常遇见的,原因就是脚本不太稳定,大多数情况下是可以通过用例的,少数情况会报这两个异常,那么我希望遇到这两种异常的时候重新跑用例脚本,代码不会因此而中断,增强了代码的健壮性。遇到未知的Exception,此时一定要raise出来,raise之前也可以自己打点日志。
3.对于webdriver的assert方法也要try一下。因为assert方法只要失败,就会抛AssertionError(感觉这种处理方式不是很好,但是又必须用selenium,通常情况应该是正确或者错误都需要返回一个值,而不是抛出一个异常呀)。except语句块主要是记录下测试用例失败的数据,然后也要raise掉。如果不raise掉,那么这个用例结果会是成功(但实际是失败了,只不过你但try让它看起来成功了)。代码如下:

    def testToolButton(self):
        logger.info("开始执行工具按钮的测试脚本...")
        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('创建书城页面,点击工具按钮,点击"我的"按钮...')
            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定义类很多异常,但是人家还是把异常信息的原因返回的很清楚。同理,我们自己在写异常的时候,抛出时也要写清楚为什么,方便别人在用的时候不知道发生了什么就抛出了异常。以下代码是一个自己定义异常的例子,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):  # 循环60次,从0至59
        if i >= 59:  # 当i大于等于59时,打印提示时间超时
            print("timeout")
            break
        try:  # try代码块中出现找不到特定元素的异常会执行except中的代码
            element.click()
        except:  # 上面try代码块中出现异常,except中的代码会执行打印提示会继续尝试查找特定的元素id
            print("wait for find element")
        else:
            break
        time.sleep(1)

以上代码是为了稳定的获取页面元素。但不得不说,这样的代码很难让人理解。代码逻辑简单还好,一旦复杂,就会跳进自己挖的坑里。

禁忌四:如果有需要,记得使用最后释放资源
这里使用java来说明下,最有名的就是数据库的操作:

package com.runoob.test;
 
import java.sql.*;
 
public class MySQLDemo {
 
    // MySQL 8.0 以下版本 - JDBC 驱动名及数据库 URL
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";  
    static final String DB_URL = "jdbc:mysql://localhost:3306/RUNOOB";
 
    // MySQL 8.0 以上版本 - JDBC 驱动名及数据库 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";
 
 
    // 数据库的用户名与密码,需要根据自己的设置
    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("连接数据库...");
            conn = DriverManager.getConnection(DB_URL,USER,PASS);
        
            // 执行查询
            System.out.println(" 实例化Statement对象...");
            stmt = conn.createStatement();
            String sql;
            sql = "SELECT id, name, url FROM websites";
            ResultSet rs = stmt.executeQuery(sql);
        
            // 展开结果集数据库
            while(rs.next()){
                // 通过字段检索
                int id  = rs.getInt("id");
                String name = rs.getString("name");
                String url = rs.getString("url");
    
                // 输出数据
                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的数据库事务操作来说明下:

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(); //批量执行 
            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

相关文章

网友评论

      本文标题:Try/Except的一点心得(selenium断言和元素操作处

      本文链接:https://www.haomeiwen.com/subject/fwajcctx.html