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
原文地址:https://www.cnblogs.com/hzhida/p/2644446.html