Selenium 使用 Selenium+Python 进行 web 自动化的疑惑

Helix · 2016年11月24日 · 最后由 jandylieu 回复于 2017年10月24日 · 2048 次阅读

如题~目前公司有个预研项目,web 这块是作为 App 的后台运营管理系统。
因为项目时间比较宽松,整个系统也比较简单,所以考虑把自动化这块做起来。
不过项目组之前没有自动化的经验,测试部门这边五个人,具备一定编程能力的就我一个。
目前的情况:
通过 Page Object 的模式,对每个功能页面构建对应的 page Object,如以下代码所示

class Login_page(App_page_object):
    def __init__(self,selenium_driver,root_url,login_url):
        super(Login_page,self).__init__(selenium_driver,root_url,login_url)
        self.url = 'login!doNotNeedSession_index.do'
        self.account_box = {'id':'cname'}
        self.password_box = {'id':'cpwd'}
        self.confirmCode_box = {'id':'confirmCode'}
        self.remenber = {'class':'checkbox'}
        self.button = {'class':'signup'}
        self.alert_msg = {'id':'myModalErrorMsg'}
        self.translate = {u'登录账号':self.account_box, u'密码':self.password_box, u'验证码':self.confirmCode_box,
                          u'记住密码':self.remenber, u'立即登录':self.button,u'提示':self.alert_msg}

对应的测试用例形式如以下所示:考虑到编写和管理方便都是在 Excel 表里边

进入 登录页面
点击 登录账号
输入 zh_app_admin
点击 密码
输入 1234567
点击 验证码
输入 1234
点击 立即登录
检查 提示=用户名或密码错误

执行测试时,通过解析函数提取每步操作方式和操作对象,依次执行测试步骤并在最后进行指定的检查,每步操作完成后,会进行截图。

昨天自己尝试写了一些用例,感觉这种方式还是太死板,目前的疑惑主要是如何比较好的进行数据驱动,把用例和数据分离开来,希望大家提供宝贵建议!

共收到 10 条回复 时间 点赞

这规则是你自己订的,想要灵活,那你胶水层的实现成本就很高。数据驱动需要加上关键字驱动,才能灵活。

#1 楼 @Lihuazhang

嗯,我之前也考虑不在用例中输入实际数据,而是用某个或某类关键字代替,执行时根据关键字自动生成或者从某处 取得数据,然后感觉这样实现起来成本太高。

另一个考虑就是直接在 page object 中封装常用的业务逻辑,这样只要传入所需参数就能执行某一个业务逻辑。

不知道您手头又没有在做 web 自动化这块,可否分享下您项目是如何进行的?

#2 楼 @pyattack PO 里面提倡放和 po 相关的业务。

自己理解的 PO 设计模式,大概这样:

1.元素定位

elements.py

def find_element(*loc):
    return driver.find_element(*loc)

def send_params(value,ipt_element):
    return ipt_element.send_keys(value)

def click_btn(*loc):
    return driver.find_element(*loc).click()

2.定位器

单独写在配置文件中,yaml,xml,ini,config 等

locators.py

login_username = (By.ID,'username')
search_btn = (By.ID,'search')
.....

3.每个页面封装该 page 经常使用到的元素或操作

例如首页搜索功能

homePage.py

def search_action(value):
     search_ipt = find_element(locators.search_ipt)
     search_btn = find_element(locators.search_btn)
     send_params(value,search_ipt) 
     click_btn(search_btn)
     return value in driver.page_source

例如购物车页面的立即结算按钮

buyCartPage.py

def order_cart():
      click_btn(find_element(*loc))

4.测试用例

testCase.py

def test_search( ):
      assertTrue search_action()


def test_order_placing():
      ....
      add_cart()
      ....
      #点击结算
      order_cart()
      ....
      assertTrue('success' in page)

以上代码写的粗略,主要表达设计思路,感觉 PO 的设计就是层层递进。
好处就是尽可能把易变的东西分离出来,以保证整体稳定性。谢谢

#3 楼 @Lihuazhang

指的是 封装常用的业务逻辑 这个么

#4 楼 @xie_0723

感谢回答!

我目前做的并没有做层层递进,App_page_object 类中封装了测试用例解析、元素定位、动作执行等公用的方法,对页面本身则会封装该页面全部或常用元素,为了用例表述的更像自然语言,对各控件名称和变量做了映射,同时,某些页面有特殊性,不适用的公共方法也会进行重写,常用操作这块目前没有做封装

总的来说 当需求发生变更,页面变更则更新 PO 本身属性,即各控件的定位方法,逻辑更新则直接更新用例 相当于只分为了逻辑层和页面属性层

#6 楼 @pyattack 如果是 UI 层的自动化,这么设计,相对已经算是比较灵活了啊,不知道你说的这种方式太死板,目前的疑惑主要是如何比较好的进行数据驱动,把用例和数据分离开来,还指哪些?是说封装好后,case 调用,写的样式都差不多吗?
你希望这样?:


test001:
      - ID:search
      - value:vaules
      - action:search

然后各种封装后调用

def case():
    #定位location()
    #输入send_keys()
    #执行动作action()

data 驱动 case

#7 楼 @xie_0723

对 就是想达到类似的效果,目前来看,还是直接在 PO 封装常用方法 然后用某个关键字进行调用这样实现吧,好在我们的页面功能都还比较简单

rf 才是真关键字驱动,其他都是伪驱动,至于数据驱动,我用的 ddt,不过 ddt 有一个大 bug,超过 10 条 case 的表格数据,顺序就会发生错乱,而不是从上到下的顺序读取。如果用 unpack 虽然可以顺序读取,但太傻还需要把每个 case 以数组参数形式列出,那就不是真正意义的数据驱动了。我看了下 java 版数据驱动用的反射机制。愿意和楼主交流,用例用 py 写,缺点不方便非测试人员。我 qq 号码:四三五一七一二三四

a1l9e8x6 回复

因为 unittest 执行时是根据 ASCII 码的顺序加载测试用例,ddt 在添加用例时,传的是 1,2,3。。。,因此在 ddt 添加用例名时,修改成个位数补两个 0,十位数补一个 0 的方法(如,001,002,012)
具体是 ddt 中 mk_test_name 方法更改成
index = index + 1
if index in range(1,10):
index = "00" + str(index)
elif index in range(10,100):
index= "0" + str(index)
test_name = "{0}{1}{2}".format(name, index, value)
如图,

希望对你有帮助

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册