• 8_17号总结


                     python自动化web测试
    
    文档包含的内容:
         1.web自动化说明与框架     2. web自动化测试例子     3.环境的搭建(附录)
         近期,由于对需要对迪备产品进行web测试,上网找了些关于python进行自动化测试的资料,发现进行Web测试,可以通过Webdriver去模拟用户的操作,当前比较出色就是splinter+selenuim,基本上支持IE,fixfox和chrome浏览器的基本操作。
        有了第三方模拟浏览器工具的帮助,然后就要想想产品的测试框架了,因为我们的产品基本上进行的是功能测试,而python自己自带的unittest是进行单元测试的,不过,似乎单元测试也是有层次的,小单元到大单元,再到一个个的模块,最后整体的软件测试。其实我们的产品的测试,也可以这样,一个个测试单元组成一个模块,例如登录迪备就是一个小模块,里面是测试单元,则是一个个的测试用例。然后再由这些小模块再组成大模块,最后成为我们产品的测试的框架。python提供了testsuit(测试包) 就是把小模块组合成大模块的类。整体来看还是典型的树形结构,同时每一层都可以有测试的进行。
        有点头绪了,就开始尝试用python进行测试了,刚开始的参数是默认的,逐渐变成从txt文件,到xml文件去读取测试用例。
        继续需要做的就是把这些测试用例做成模块,构架出框架来。
    以下些例子:主要参考
    http://splinter.cobrateam.info/docs/ splinter的官网,自动测试的Web框架,包含小例子和API的说明
    http://docs.python.org/library/unittest.html python单元测试框架的文档和小例子
    http://docs.python.org/library/xml.etree.elementtree.html python对XML的解析
    另外还需要了解一下html,css,和javacript
    其实这只是例子,真正的还需要很多的细化。
    例子1:批量增加,删除用户,增加ftp服务器,删除ftp服务器的参数都从XML文件中读取,并可以从server端的mysql数据库获取数据来assertEqual.
    例子2:创建oracle数据库备份实例和mysql数据库备份实例,在备份之前先往数据库里面添加数据,在恢复后,再查询是否同样的数据在数据库中(未完成)
    xml文件在以后就变成测试用例输入的数据,如边界值,只需要修改xml文件,再运行python脚本来测试
    username.xml
    <?xml version = "1.0" encoding= "UTF-8"?> 
    <addUsers> 
        <user name='hzhida' password = 'dingjia' email ='hzhida95@gmail.com' telephone='13424341233' /> 
        <user name='dingjia' password= 'dingjia' email ='dbackup@gmail.com'  telephone= '3143142131' /> 
        <user name = 'Tommy' password = 'djifadf' email ='34131431@qq.com'   telephone ='1341314312'/> 
        <user name = 'Janny' password = 'dafjljfd' email ='erfdjlafj@qq.com' telephone = '143143134'/> 
    </addUsers>
    ftp.xml
    <?xml version = "1.0" encoding= "UTF-8"?> 
    <TotalFTP> 
        <ftp name='ftpunbuntu' ip='192.168.88.245' port ='21' username = 'hzhida' password = 'dingjia' path ='FTPFile/backup/'/> 
        <ftp name='windowftp' ip='192.168.88.162' port = '21' username = 'hzhida' password = 'dingjia' path='FTPFile\backup'/> 
    </TotalFTP>
    
    #-*-coding:utf-8-*- 
    from __future__ import with_statement 
    import os 
    import unittest 
    import time 
    from splinter import Browser 
    from random import randint 
    from xml.etree import ElementTree as ET 
    import MySQLdb 
    
    class DbackupTestCase(unittest.TestCase): 
    
        @classmethod 
        def setUpClass(cls): 
            cls.browser = Browser('firefox') 
            cls.connection = MySQLdb.connect(user='scutech',db ='dpsora_1',passwd='dingjia',host='192.168.88.245') 
            cls.cursor = cls.connection.cursor() 
    
        @classmethod 
        def setDownClass(cls): 
            cls.browser.quit() 
    
        def login(self, username, password): 
            if self.browser.find_by_id('lhgfrm_lhgdgId'): 
                with self.browser.get_iframe('lhgfrm_lhgdgId') as frame: 
                    frame.find_by_id('trialRadio').click() 
                    frame.find_by_id('continue').click() 
    
            self.browser.fill('username',username) 
            self.browser.fill('password',password) 
            self.browser.find_by_name('Submit').click() 
            time.sleep(0.5) 
            assert self.browser.is_element_present_by_tag('body') 
    
        #@unittest.skip('skip register') 
        def test_register(self): 
            self.browser.visit('http://192.168.88.245/dbackup') 
            self.login(username='admin', password= 'admin') 
            time.sleep(1) 
            #because iframe has no id,so can't get it 
            #iframe = self.browser.find_by_tag('iframe') 
            #iframe.find_link_by_href('../Supermanage/LocalCfgManage.php').click() 
    
            #self.browser.find_by_id('Navigate1').click() 
            #self.browser.find_link_by_href('Register.php').click() 
            navigate = self.browser.find_by_css('.NavigateMBG') 
            for i in navigate: 
                print i 
            navigate[2].click() 
            navigate[2].find_by_tag('a')[2].click() 
            time.sleep(0.5)     
            file = ET.parse('username.xml') 
            users = file.findall('./user') 
            for user in users: 
                self.browser.find_by_id('username').fill(user.get('name')) 
                self.browser.fill('password',user.get('password')) 
                self.browser.find_by_id('confirmpassword').fill(user.get('password')) 
                self.browser.find_by_id('email').fill(user.get('email')) 
                self.browser.find_by_id('telephone').fill(user.get('telephone')) 
                self.browser.find_by_name('Submit').click() 
                time.sleep(1) 
                alert = self.browser.get_alert() 
                alert.accept() 
    
                #select from database to check whether the user had registered 
                self.cursor.execute("""select username from v_loginaccountinfo where enabled = '1' and username= %s""" , (user.get('name'),)) 
                self.assertEqual(self.cursor.fetchone(),(user.get('name'),)) 
     
                #navigate[2].click() 
                #navigate[2].find_by_tag('a')[2].click() 
                self.browser.find_by_id('Navigate1').click() 
                self.browser.find_link_by_href('Register.php').click() 
            
    
        
        @unittest.skip('skip user land') 
        def test_User(self): 
            self.browser.visit('http://192.168.88.245/dbackup') 
            file = ET.parse('username.xml') 
            users = file.findall('./user') 
            for user in users: 
                self.login(username = user.get('name'), password = user.get('password')) 
                time.sleep(1) 
                iframe =  self.browser.find_by_tag('iframe') 
                iframe[0].find_by_tag('a')[3].click() 
                self.browser.visit('http://192.168.88.245/dbackup') 
    
        @unittest.skip('del user') 
        def test_delUser(self): 
            self.browser.visit('http://192.168.88.245/dbackup') 
            self.login(username ='admin', password ='admin') 
            time.sleep(0.5) 
            navigate = self.browser.find_by_css('.NavigateMBG') 
            navigate[2].click() 
            navigate[2].find_by_tag('a')[1].click() 
            table=self.browser.find_by_id('mytable') 
            tr=table.find_by_tag('tr') 
            file = ET.parse('deluser.xml') 
            user = file.find('./user') 
            i=1 
            while i< len(tr): 
                if tr[i].find_by_tag('td')[1].value == user.get('name'): 
                    tr[i].find_by_tag('input').click() 
                    self.browser.find_by_id('nDeleteAccountID').click() 
                    time.sleep(1) 
                    alert = self.browser.get_alert() 
                    alert.accept() 
                    alert = self.browser.get_alert() 
                    alert.accept() 
                    time.sleep(1) 
                    break 
                else: 
                    i+=1 
    
        @unittest.skip('skip addFTP') 
        def test_addFTP(self): 
            self.browser.visit('http://192.168.88.245/dbackup') 
            self.login(username = 'admin', password = 'admin') 
            time.sleep(0.5) 
            navigate = self.browser.find_by_css('.NavigateMBG') 
            navigate[0].click() 
            navigate[0].find_by_tag('a')[2].click() 
            file = ET.parse('ftp.xml') 
            ftps = file.findall('./ftp') 
            for ftp in ftps: 
                self.browser.find_by_id('strFTPNameID').fill(ftp.get('name')) 
                ip = [ ftp.get('ip').strip().split('.') for ipnum in ftp.get('ip') ] 
                self.browser.find_by_id('IP1').fill(ip[0][0]) 
                self.browser.find_by_id('IP2').fill(ip[0][1]) 
                self.browser.find_by_id('IP3').fill(ip[0][2]) 
                self.browser.find_by_id('IP4').fill(ip[0][3]) 
                self.browser.find_by_id('strPortID').fill(ftp.get('port')) 
                self.browser.find_by_id('strFTPLoginNameID').fill(ftp.get('username')) 
                self.browser.fill('strFTPLoginPW',ftp.get('password')) 
                self.browser.find_by_id('ConfirmPWID').fill(ftp.get('password')) 
                self.browser.find_by_id('nPathID').fill(ftp.get('path')) 
                self.browser.find_by_id('Submit').click() 
                alert = self.browser.get_alert() 
                alert.accept() 
                time.sleep(1) 
                self.cursor.execute("""select FtpName from ftpserver where Disabled ='0' and FtpName = %s""",(ftp.get('name'),)) 
                self.assertEqual(self.cursor.fetchone(),(ftp.get('name'),)) 
                self.browser.find_by_id('Navigate5').click() 
                self.browser.find_link_by_href('FtpCfg.php').click() 
    unittest.main()        
    
       例子2:
    #-*-coding:utf-8-*- 
    from __future__ import with_statement 
    import os 
    try: 
        import unittest2 as unittest 
    except ImportError: 
        import unittest 
    import time 
    from splinter import Browser 
    from random   import randint 
    import cx_Oracle 
    import mySQLdb 
    import cPickle 
    from sys import modules 
    
    class DbackupTestCase(unittest.TestCase): 
       # support 2.7,but not support 2.6.all the testcases just have one instance 
        @classmethod 
        def setUpClass(cls): 
            cls.browser=Browser('firefox') 
            cls.connection =cx_Oracle.connect('system','dingjia','192.168.88.245/oracle') 
            cls.cursor =cls.connection.cursor() 
        
        @classmethod 
        def setDownClass(cls): 
             cls.browser.quit() 
    
       #every testcase has one instance 
       # def setUp(self): 
       #     self.browser=Browser('firefox') 
    
       # def setDown(self): 
       #     self.browser.quit() 
    
        def do_login_if_need(self, username, password): 
    
            if self.browser.find_by_id('lhgfrm_lhgdgId'): 
                    with self.browser.get_iframe('lhgfrm_lhgdgId') as frame: 
                        frame.find_by_id('trialRadio').click() 
                        frame.find_by_id('continue').click() 
    
            self.browser.fill('username',username) 
            self.browser.fill('password',password) 
            self.browser.find_by_name('Submit').click() 
    
            assert  self.browser.is_element_present_by_css('.none') 
            
    
        def test_create_oracle_event(self): 
            #In order to check the backup process is correct, so before it backup,insert some data in database, and when it recover,so it is a chance to select the same data in database to terify the process of backup 
            create_table=""" 
                create table python_modules( 
                module_name VARCHAR2(50) NOT NULL, 
                file_path VARCHAR2(300) NOT NULL 
                )""" 
            self.cursor.execute(create_table) 
            M= [] 
            for m_name, m_info in modules.items(): 
                try: 
                    M.append((m_name,m_info.__file__)) 
                except AttributeError: 
                    pass 
            cursor.prepare("insert into python_modules(module_name,file_path) values(:1,:2)") 
            cursor.executemany(None,M) 
            #submit transation 
            self.connection.commit() 
    
            #open home and login 
            self.browser.visit('http://192.168.88.245/dbackup') 
            self.do_login_if_need(username='hzhida', password ='dingjia') 
            time.sleep(0.5) 
            assert self.browser.is_element_present_by_id('treeNodeId1') 
            self.browser.find_link_by_href('javascript:void(0)')[1].click() 
            time.sleep(1) 
            element=self.browser.find_by_css('.tree_item_child') 
            #self.browser.find_link_by_href('javascript:void(0)')[2].click() 
            element[0].find_by_css('.tree_item_click').first.click() 
            #element[0].find_by_tag('a').first.click() 
            self.browser.find_by_id('Navigate7').click() 
            time.sleep(1) 
            self.browser.find_link_by_href('#wizard-2').click() 
            self.browser.find_link_by_href('#wizard-3').click() 
            self.browser.find_by_id('ftpRadio').click() 
            self.browser.find_link_by_href('#wizard-4').click() 
            number = [randint(1000,9999) for i in range(1)] 
            jobname='job'+'_'+ str(number[0]) 
            self.browser.find_by_id('jobName').fill(jobname) 
            self.browser.find_by_id('middlelevelRadio').click() 
            self.browser.find_link_by_href('#wizard-5').click() 
            self.browser.find_by_css('.submit_btn').click() 
            time.sleep(1) 
            self.browser.select('Filtermenu','JobMonitorManage.php?FType=1') 
            time.sleep(0.1) 
            self.browser.select('Filtermenu','JobMonitorManage.php?FType=0') 
            time.sleep(0.1) 
            self.assertEqual(self.browser.find_link_by_href('javascript:void(0)').first.value,jobname) 
            print self.browser.find_by_id('CompletePercent0').value 
            print self.browser.find_by_id('strBeginTime0').value 
            print self.browser.find_by_id('strUsedTime0').value 
            time.sleep(10) 
        
        @unittest.skip('skip test mysql') 
        def test_create_mysql_event(self): 
    
            self.browser.visit('http://192.168.88.245/dbackup') 
            self.do_login_if_need(username='hzhida',password='dingjia') 
            time.sleep(0.5) 
            assert self.browser.is_element_present_by_id('treeNodeId1') 
            self.browser.find_link_by_href('javascript:void(0)')[1].click() 
            time.sleep(1) 
            element=self.browser.find_by_css('.tree_item_child') 
            element[1].find_by_tag('a').first.click() 
            self.browser.find_by_id('Navigate7').click() 
            self.browser.find_by_id('sqlSelectAllCheckbox').click() 
            time.sleep(2) 
            navigate=self.browser.find_by_css('.nav') 
            navigate[0].find_by_css('.next').click() 
            self.browser.find_by_id('ftpRadio').click() 
            navigate[1].find_by_css('.back').click() 
            time.sleep(1) 
            navigate[0].find_by_css('.next').click() 
            navigate[1].find_by_css('.next').click() 
            self.browser.find_by_id('lowlevelRadio').click() 
            number = [randint(1000,9999) for i in range(1)] 
            jobname= 'job'+'_'+str(number[0]) 
            self.browser.find_by_id('jobName').fill(jobname) 
            navigate[2].find_by_css('.next').click() 
            navigate[3].find_by_css('.submit_btn').click() 
            self.assertEqual(self.browser.find_by_tag('font').value, jobname) 
            print self.browser.title() 
            print self.browser.html 
    unittest.main()
    
    附录:
    Ubuntu 11.10 安装splinter
    为了防止下面的过程出错,建议:
        sudo apt-get install build-essential python-dev libxml2-dev libxslt1-dev
    1.下载splinter 0.4.7.tar.gz包  http://pypi.python.org/pypi/splinter/0.4.7/
    2.解压 tar -zxvf 安装包  进入cd splinter 0.4.7
    3.安装 sudo python setup.py install
        ImportError: No module named setuptools
        wget http://pypi.python.org/packages/source/s/setuptools/setuptools-0.6c11.tar.gz
          tar zxvf setuptools-0.6c11.tar.gz
        cd setuptools-0.6c11
        python setup.py build
        python setup.py install
     安装过程中提示
    make sure the development packages of libxml2 and libxslt are installed **
    
      Using build configuration of libxslt
      src/lxml/lxml.etree.c:4: fatal error: Python.h: 没有那个文件或目录
      compilation terminated.
      error: Setup script exited with error: command 'gcc' failed with exit status 1
      经过google查询得知没有安装libxml2-dev和libxlst1-dev
    为保险起见,请依次安装如下:
      sudo apt-get install gcc
      sudo apt-get install python-dev
      sudo apt-get install libxml2 libxml2-dev
      sudo apt-get install libxslt1.1 libxslt1-dev
      后面的是数字1,不是字母l,不要写错了。
    AttributeError: 'NoneType' object has no attribute 'clone' 到http://pypi.python.org/pypi/setuptools/ 下载ez_setup.py
    执行python ez_setup.py -U setuptools 升级setuptools 过程中可能会出现网络的错误,如connection peer ,可以重复执行一下
    支持浏览器fixfox,chrome,IE 还需下载安装http://pypi.python.org/pypi/selenium/
    下载selenium-2.25.0.tar.gz
    解压 tar -zxvfselenium-2.25.0.tar.gz
    cd    selenium-2.25.0
    sudo python setup.py install    这样就可以模拟浏览器的操作
    
    环境基本搭建好了,如果想用python去操作mysql数据库和oracle数据库, 还需安装:
    MySQLdb模块 和 cx_Oracle模块
    安装MySQLdb模块:
         首先安装MySQL数据库,在Ubuntu可以直接apt-get mysql,对于其他的系统,如Redhat 可以到oracle官网上下载mysql.rpm安装文件
        使用命令rpm -ivh mysql-server.rpm 和rpm -ivh mysql-client.rpm 进行安装
        假如发生包mysql-lib冲突,可以yum erase 或者yum remove 来把冲突的包给去掉。
        ubuntu 系统:sudo apt-get install python-mysqldb
        另外其他系统:下载 MySQL-python-1.2.3.tat.gz (下载地址Google下)
          解压后 sudo python setup.py build
          提示: ImportError: No module named setuptools (没有setuptools 模块)
          继续下载 setuptools-0.6c11.tar.gz
          解压后 sudo python setup.py build (编译)
          sudo python setup.py install (安装)
          这回有 setuptools模块了吧!
          回到用户MySQLdb源码目录
    
          继续sudo python setup.py build 又提示:mysql_config not found
          于是乎查mysql_config
          得知mysql_config是属于MySQL开发用的文件,而使用apt-get安装的MySQL是没有这个文件的,于是在包安装器里面寻找
          libmysqld-dev
          libmysqlclient-dev
          这两个包安装后问题即可解决
          这回/usr/bin/ 下有 mysql_config命令了 (查找命令 whereis mysql_config)
          修改MySQLdb下的setup_posix.py 文件 
          找到mysql_config.path 改成mysql_config.path = "/usr/bin/mysql_config"//就是mysql_config.path=XXXX的这行。
          在重复: sudo python setup.py build
          又出错: error: command 'gcc' failed with exit status 1
          sudo apt-get install build-essential
          sudo apt-get install python-dev
          安完以后在回到MySQLdb目录
          sudo python setup.py build (编译)
          sudo python setup.py install (安装)
    
    安装cx_Oracle模块:
    
        Oracle Instant Client is a free Oracle database client. The current version is 11.2.0.1.0, and several versions back to 10.1.0.5 are available.
    Install RPMs
    Download the Oracle Instantclient RPM files fromhttp://www.oracle.com/technetwork/database/features/instant-client/index-097480.html. Everyone needs either "Basic" or "Basic lite", and most users will want "SQL*Plus" and the "SDK".
    Convert these .rpm files into .deb packages and install using "alien" ("sudo apt-get install alien" if you don't have it):
    转为位deb包,然后直接安装
    alien -i  oracle-instantclient11.2-basic-11.2.0.3.0-1.x86_64.rpm
    alien -i oracle-instantclient11.2-devel-11.2.0.3.0-1.x86_64.rpm
    alien -i oracle-instantclient11.2-sqlplus-11.2.0.3.0-1.x86_64.rpm
    由于是rpm包,在ubuntu上转换位deb包:sudo alien oracle-instantclient-basic-11.2.x86_64.rpm
    得到deb包,在ubuntu上安装命令为:sudo dpkg -i oracle-instantclient-basic_11.2_amd64.deb
    Test your Instantclient install by using "sqlplus" to connect to your database:
    sqlplus  username/password@//dbhost:1521/SID
    If sqlplus complains of a missing libaio.so.1 file, run
    sudo apt-get install libaio1
    If sqlplus complains of a missing libsqlplus.so file, follow the steps in the section "Integrate Oracle Libraries" below.
    If you execute sqlplus and get "sqlplus: command not found", see the section below about adding the ORACLE_HOME variable.
    Integrate Oracle Libraries|ORACLE_HOME
    If oracle applications, such as sqlplus, are complaining about missing libraries, you can add the Oracle libraries to the LD_LIBRARY_PATH each time it is used, or to add it to the system library list create a new file as follows:
    sudo vim /etc/profile
    增加以下环境变量:
            export ORACLE_HOME=/usr/lib/oracle/11.2/client64
      export PATH=$PATH:$ORACLE_HOME/bin
      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME/lib
      export TNS_ADMIN=$ORACLE_HOME/network/admin
    source /etc/profile 文件 更新环境变量
    如果需要配置tnsnames.ora还需要这样操作:
    sudo mkdir -p $ORACLE_HOME/network/admin
    sudo cp tnsnames.ora $ORACLE_HOME/network/admin
    Download and build cx_Oracle
    Download cx_Oracle at http://cx-oracle.sourceforge.net and unzip wherever you want, then...
    选择源码安装:解压下载回来的tar.gz包,tar -zxvf cx_oracle.tar.gz
    cd [your cx_Oracle installation path]
    python setup.py build
    python setup.py install
      ImportError: libclntsh.so.11.1: cannot open shared object file: No such file or directory
      此时是由于python在操作oracle数据库的时候需要用到oracle的一些库,而上面的问题就是说python需要的这些库不在环境的路径里,在linux上就是不在LD_LIBRARY_PATH环境变量里,此时时就需要把这些库路径加到LD_LIBRARY_PATH中
    $exportLD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/lib/oracle/11.2/client64/lib 
    也可以选择rpm安装,解压出来里面有cx_Oracle.so ,执行命令:sudo cp cx_Oracle.so /usr/local/lib/python2.7/dist-packages/
    验证安装成功:
    luca@ubuntu:~$ python
    [GCC 4.4.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import cx_Oracle
    >>> print cx_Oracle.version
    5.1.2
  • 相关阅读:
    关于打字的思考
    apisix插件开发非对称性加签验签
    apisixFAQ
    idea插件力扣
    apisix开启gzip
    apisixnginx配置
    无重复字符的最长子串第一名代码解释记录
    apisixnginxheader内容转义
    红黑树新增
    apisix插件开发值的获取
  • 原文地址:https://www.cnblogs.com/hzhida/p/2644446.html
Copyright © 2020-2023  润新知