第六章 自动测试实施(下)

---Web自动化测试之Webdriver(python)--从零到熟练(系列)

6.6 编写自动化测试用例

   我们规划好了代码架构,就可以编写具体的测试用例了。首先,我们写登录的测试用例,在写自动化测试用例的时候,我们要先写一下公用函数类。根据需要,我们写了三个通用的类放到CommonFunction文件夹下:WebDriverHelp用来存放所有页面操作用到公用方法;QT_Operations 用来存放具体操作功能块,如登录,退出等;DataOperations用来存放所有数据操作,用来读取xml中的测试数据。

然后我们在TestCases文件夹下编写登录的测试用例TestCase_QT_Login.py执行具体的测试操作,验证测试用例执行是否成功。

并把测试用例需要的测试数据,放到TestData文件夹下TestCase_QT_Login.xml文件中。如果网站有所变化,可以修改这个里面的测试数据,从而减少代码维护的成本。

6.6.1 WebDriverHelp类的内容

WebDriverHelp是我们所有测试用例能用到的方法,可以在编写测试过程中不断抽象出来,写到这个类里面,相当于对Webdriver再次做了一下封装。

下面是部分代码,以供大家参考:

@author:songxianfeng

@copyright: V1.0

'''

import time

import datetime

from selenium import webdriver

from selenium.webdriver.support.ui import Select

 

from selenium.common.exceptions import NoSuchElementException

from selenium.webdriver.common.action_chains import ActionChains

from selenium.webdriver.common.keys import Keys

global G_WEBDRIVER, G_BROWSERTYTPE,DRIVER

 

class WebDriverHelp(object):

    '''

    本类主要完成页面的基本操作,如打开指定的URL,对页面上在元素进行操作等

    '''

 

    def  __init__(self,btype="close",atype="firefox",ctype="local"):

        '''

        根据用户定制,打开对应的浏览器

        @param bType: 开关参数,如果为close则关闭浏览器

        @param aType:打开浏览器的类型,如chrome,firefox,ie等要测试的浏览器类型

        @param cType:打开本地或是远程浏览器: local,本地;notlocal:远程        '''

        global DRIVER

        if(  btype == "open" ):           

            if(  atype == "chrome" ):

                if(ctype == "local"):   

                    DRIVER = webdriver.Chrome()

                    DRIVER.maximize_window()

                elif(ctype == "notlocal"):                

                    DRIVER = webdriver.Remote(command_executor='http://124.65.151.158:4444/wd/hub', desired_capabilities=webdriver.DesiredCapabilities.CHROME)

                    DRIVER.maximize_window()                   

            elif(  atype == "ie" ):

                if(ctype == "local"): 

                    DRIVER = webdriver.Ie()

                    DRIVER.maximize_window()

                elif(ctype == "notlocal"):                  

                    DRIVER = webdriver.Remote(command_executor='http://124.65.151.158:4444/wd/hub',desired_capabilities=webdriver.DesiredCapabilities.INTERNETEXPLORER)

                    DRIVER.maximize_window()                   

            elif(  atype == "firefox" ):

                if(ctype == "local"):

                    DRIVER = webdriver.Firefox()

                    DRIVER.maximize_window()

                elif(ctype == "notlocal"):                  

                    DRIVER = webdriver.Remote(command_executor='http://10.20.5.56:4444/wd/hub',desired_capabilities=webdriver.DesiredCapabilities.FIREFOX)

                    DRIVER.maximize_window() 

                                  

        self.DRIVER = DRIVER

 

    def  setup(self,logintype):

        '''

        定制测试URL

        @param loginplace: 指定测试的URL qiantai:前台测试地址,houtai:后台测试地址,zhengshi:正式环境测试地址

        ysh:原始会测试地址 zhengshiysh:正式原始会测试地址

        '''

        try:

            qiantai_url = "http://test.zhongchou.cn"

            ysh_url = "http://test.ysh.zhongchou.cn" 

            houtai_url = "http://test.admin.zhongchou.cn"

            zhengshi_url = "http://www.zhongchou.cn"

            zhengshi_ysh_url = "http://ysh.zhongchou.cn"

 

            if(logintype=="qiantai"):

                self.DRIVER.get(qiantai_url)

            elif(logintype=="houtai"):

                self.DRIVER.get(houtai_url)

            elif(logintype=="zhengshi"):

                self.DRIVER.get(zhengshi_url)

            elif(logintype=="ysh"):

                self.DRIVER.get(ysh_url)

            elif(logintype=="zhengshiysh"):

                self.DRIVER.get(zhengshi_ysh_url)

            else:

                print '路径错误!'

            self.DRIVER.implicitly_wait(1)

        except NoSuchElementException:

            print '您选择的测试地址出错!!'      

    def  teardown(self):

        '''

        关闭浏览器

        '''       

        self.DRIVER.quit()

                

    def  geturl(self,url):

        '''

        打开指定的网址

        @param url: 要打开的网址

        '''

        self.DRIVER.get(url)    

def  selectvalue(self,findby,select,selectvalue):

        '''

        通过定制定位方法和要选择项的文本,选择指定的项目

        @param findby:定位方法,如:byid,byname,byclassname

        @param select: 要执行选择操作的下拉框句柄

        @param selectvalue: 下拉框中要选择项的文本

        '''

        if(findby == 'byid'):

            select = Select(self.findelementbyid(select))

        elif(findby =='byname'):

            select = Select(self.findelementbyname(select))

        elif(findby =='byclassname'):

            select = Select(self.findelementbyclassname(select))

        select.select_by_visible_text(selectvalue)

      

    def  inputvalue(self,findby,elmethod,value):

        '''

        通过定制定位方法,在输入框中输入值

        @param findby: 定位方法,如:byid,byname,byclassname,byxpath

        @param elmethod: 要定位元素的属性值 ,如:id,name,class name,xpath

        @param value: 要给文本框输入的值

        '''

        if(findby == 'byid'):

            self.findelementbyid(elmethod).send_keys(value)

        elif(findby == 'byname'):

            self.findelementbyname(elmethod).send_keys(value)

        elif(findby =='byclassname'):

            self.findelementbyclassname(elmethod).send_keys(value)

        elif(findby == 'byxpath'):

            self.findelementbyxpath(elmethod).send_keys(value)

      …… 

上面的代码都有很详细的注释,在此就不一一讲述了。

6.6.2 QT_Operations类的内容

QT_Operations类是业务相关的公用功能块的封装,以便增加函数的公用性,减少代码量。例如,登录,在很多测试用例的第一步都需要先登录再操作的。所以你可以抽像出测试用例中的功能模块,封装后放到这个类中。

QT_Operations类的部分代码展示:

#-*- coding: UTF-8 -*-

'''

Created on 2014-12-15

@author:songxianfeng

@copyright: V1.0

'''

import time

import win32api

import win32con

 

from WebDriverHelp import WebDriverHelp

 

class QT_Operations(object):

    '''

    众筹前台相关操作

    '''

    def login(self,userName,passwd):

        '''

        从首页直接登录

        @param userName: 用户名

        @param passwd:密码

        @param type1:指示登录方式,1为从主页登录,2,从登录页登录

        '''

        WebDriverHelp().clickitem("byclassname", "Js-showLogin")

        time.sleep(3)

        WebDriverHelp().clearvalue('byname','username')

        WebDriverHelp().inputvalue('byname','username',userName)

        WebDriverHelp().clearvalue('byname','user_pwd')

        WebDriverHelp().inputvalue('byname','user_pwd',passwd)

        time.sleep(1)

        WebDriverHelp().clickitem("byclassname", "a-btn")

        time.sleep(5)

       

    def logout(self):

        '''

        退出登录

        '''

        WebDriverHelp().geturl("http://www.zhongchou.cn/usernew-loginout")

……

展示部分只包含了登录和退出功能,其他的功能可以根据测试用例的需要进行添加。

6.6.3 DataOperations类的内容

   DataOperations类是对测试数据进行读取的操作,我们是用xml来存放测试数据的,所以测试用例执行的时候,需要先将测试数据读取出来,传递给相应的函数来对测试用例进行执行。然后根据执行的结果,判断测试用例是否执行成功。

DataOperations的内容:

#-*- coding: UTF-8 -*-

'''

Created on 2014-12-15

@author:songxianfeng

@copyright: V1.0

'''

import MySQLdb

from xml.dom import minidom

global DOC,CONN

 

class DataOperations(object):   

    '''

    数据读取相关操作

    '''

 

    def __init__(self,filename):

        '''

        初始化xml文档

        '''

        global DOC,CONN

        DOC = minidom.parse("../testData/"+filename) 

          

    def readxml(self,ftagname,num,stagname):

        '''

        从指定的文件中中读取指定节点的值

        @param ftagname:起始节点的名称,如:project

        @param num:取与起始节点相同的第num个节点

        @param stagname: 起始节点下的二级节点

        @return: 返回二级节点的值

        '''          

        root = DOC.documentElement

        message=root.getElementsByTagName_r(ftagname)[num]

        return message.getElementsByTagName_r(stagname)[0].childNodes[0].nodeValue

   

    def readxml_attribute(self,ftagname,num,stagname,attributeName):

        '''

        all_case.xml文件中读取节点的属性值

        @param ftagname:起始节点的名称,如:project

        @param num:取与起始节点相同的第num个节点

        @param stagname: 起始节点下的二级节点

        @param attributeName: 二级节点的属性名

        @return:返回二级节点指定的属性值       

        '''

      

        root = DOC.documentElement

        message=root.getElementsByTagName_r(ftagname)[num]

        return message.getElementsByTagName_r(stagname)[0].getAttribute(attributeName)

 

pythonxml的读取操作,如果你不太明白,可以去自行学习相关的内容,要教程不讲解相关的操作。

6.6.3 具体的测试用例

  上面的公用方法类创建以后,我们就可以着手编写具体的测试用例了。在TestCases文件夹下创建测试用例TestCase_QT_Login.py,然后编写下面的测试步骤:

(1)            打开众筹网。

(2)            点击登录按钮,输入用户名和密码。

(3)            验证是否登录成功,用户昵称是不是刚刚登录的账号。

(4)            退出登录,关闭浏览器。

测试用例代码如下:

-*- coding: UTF-8 -*-

'''

Created on 2014-12-15

@author:songxianfeng

@version: v1.0

'''

import unittest

import time

#导入需要的公共函数类

from CommonFunction.WebDriverHelp import WebDriverHelp

from CommonFunction.DataOperations import DataOperations

from CommonFunction.QT_Operations import QT_Operations

class testcases_login(unittest.TestCase):

    '''

    登录检测

    '''

    def setUp(self):

        WebDriverHelp("open","firefox","local").setup("zhengshi")#打开浏览器,并打开众筹网

       

    def testlogin(self):       

        #登录检测       

        dataoper=DataOperations("TestCase_QT_Login.xml") #读取测试数据

        #登录      

        QT_Operations().login(dataoper.readxml('login', 0, 'username'),

dataoper.readxml('login', 0, 'password'))

        self.assertEqual(WebDriverHelp().gettext('byxpath',dataoper.readxml('login', 0, 'checkpoint1')),dataoper.readxml('login', 0, 'value1')) #判断登录是否成功

        #退出

        QT_Operations().logout()

        time.sleep(5)

        self.assertEqual(WebDriverHelp().gettext('byclassname',dataoper.readxml('login', 0, 'checkpoint2')),dataoper.readxml('login', 0, 'value2')) #判断退出是否成功

                        

    def tearDown(self):

        WebDriverHelp().teardown()#关闭浏览器

       

if __name__ == "__main__":   

unittest.main()

 

经过我们上面的封装,现在具体的测试用例只是传参数,调用具体的函数,验证执行结果。是不是非常简单?有点儿像我们小时候玩积木,用一块块现成的积木堆积出魔幻的城堡。

6.6.4 测试用例的具体数据

   由于我们把测试用例和测试数据完全分离开了,所以我们用和测试用例同名的文件名命名对应的测试数据文件。登录测试用例的数据文件是TestCase_QT_Login.xml,具体内容如下:

 

原文地址:https://www.cnblogs.com/eagleking0318/p/6520876.html