selenium UI自动化实战

Posted 点哥1314

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了selenium UI自动化实战相关的知识,希望对你有一定的参考价值。

一.前言

1.1项目框架

项目如何使用框架: 本项目采用unitest框架
设计模式是如何应用:本项目采用pageobject设计模式
UI对象库思想
项目设计

一个模块(被测项目的页面)对应一个py文件及一个测试类(测试文件)
每一个测试页面(系统的页面)中存储页面元素及此页面中涉及到的功能
每一个用例组合在一个测试类里面生成一个py文件

项目目标
我们在写自动化测试项目的时候一定要想好你的脚本都要哪些功能,页面元素平凡改动的时候是否需要大批量的修改脚本,及测试不同数据时是否也要修改脚本,那么能想到这些我们的初始目标差不多就有了

  1. 生成测试用例执行结果报告
    2.生成测试用例执行日志
    3.用例执行失败或者执行完成后自动发送邮件报告
  2. 用例执行失败或者成功时截取图片
    5.数据驱动(读取测试数据,减少脚本维护成本)

更多资料

1.2项目目录结构

Retail_TestPro
    Docs# 存放项目的相关文档        
        01测试计划
        02测试大纲
        03测试用例
        04测试报告
        05测试进度
        06技术文档
        07测试申请
    Package# 存放第三方插件
        htmlTestRunner.py
    Retail
        Config
            __init__.py
            Conf.py# 读配置文件获取项目跟目录路径 并获取所有欲使用的目录文件的路径
            Config.ini# 存放项目跟目录的路径
        Data
            TestData
                __init__.py
                elementDate.xlsx# 存放项目中所有的元素信息及测试数据
                Email_receiver.txt# 存放邮件的接受者信息
        Report# 测试报告
            Image
                Fail# 存放用例执行失败时的截图
                Pass# 存放用例执行成功时的截图
            Log# 存放用例执行过程中的log信息
            TestReport# 存放测试用例执行完成后生成的测试报告
        Test_case# 测试用例信息
            Models # 存放一些公共方法
                Doconfini.py# 读配置文件
                Doexcel.py# 读excel文件
                Driver.py# 存放driver
                Log.py# 生成log
                Myunit.py# 继承unittest.Testcase
                Sendmail.py# 发送邮件
                Strhandle.py# 字符串处理
                Tcinfo.py# 测试用例基本信息
                Testreport.py# 测试报告
            Page_obj# 测试模块
                Activerule_page.py
                Base_page.py
                Company_page.py
                Createrule_page.py
                Memberquery_page.py
                Modifypw_page.py
                Pointquery_page.py
                ActiveRuleTc.py
                CompanyQueryTc.py
                CreateRuleTc.py
                LoginTc.py
                MemberQueryTc.py
                ModifyPwTc.py
                PointQueryTc.py
        runTc.py# 执行测试用例         

代码目录

二.项目代码

1.config.ini (存放项目跟路径)

[project]
project_path = D:\\Petrochina_Retail_Test_Project

2.conf.py

'''
 Code description:read config.ini, get path
 Create time:
 Developer:
 '''
 import os
 import sys
 from retail.test_case.models.doconfIni import DoConfIni
 
 # 获取当前路径
 currPath= \\
     os.path.split(os.path.realpath(__file__))[0]
 
 # 读配置文件获取项目路径
 readConfig = \\
     DoConfIni()
 proPath = \\
     readConfig.getConfValue(os.path.join(currPath,'config.ini'),'project','project_path')
 
 # 获取日志路径
 logPath= \\
     os.path.join(proPath,'retail','report','Log')
 
 # 测试用例路径
 tcPath = \\
     os.path.join(proPath,'retail','test_case')
 
 # 获取报告路径
 reportPath= \\
     os.path.join(proPath,'retail','report','TestReport')
 
 # 获取测试数据路径
 dataPath= \\
     os.path.join(proPath,'retail','data','TestData')
 
 # 保存截图路径
 # 错误截图
 failImagePath = os.path.join(proPath, 'retail', 'report', 'image','fail')
 # 成功截图
 passImagePath = os.path.join(proPath, 'retail', 'report', 'image','pass')
 
 # 被调函数名称
 funcName = sys._getframe().f_code.co_name
 # 被调函数所在行号
 funcNo = sys._getframe().f_back.f_lineno
 
 # 被调函数所在文件名称
 funcFile= sys._getframe().f_code.co_filename

3.elementData.xlsx(json与yaml替换)

存放测试数据

4.公共方法models下面的文件

4.1doconfini.py

 '''
 Code description:read conf file
 Create time:
 Developer:
 '''
 
 import logging
 import configparser
 from retail.config.conf import *
 from retail.test_case.models.log import Logger
 
 log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
 class DoConfIni(object):
 
     def __init__(self):
         """
 
         :param filename:
         """
         self.cf = configparser.ConfigParser()
 
     # 从ini文件中读数据
     def getConfValue(self,filename,section,name):
         """
 
         :param config:
         :param name:
         :return:
         """
         try:
             self.cf.read(filename)
             value = self.cf.get(section,name)
         except Exception as e:
             log.logger.exception('read file [%s] for [%s] failed , did not get the value' %(filename,section))
             raise e
         else:
             log.logger.info('read excel value [%s] successed! ' %value)
             return value
     # 向ini文件中写数据
     def writeConfValue(self,filename, section, name, value):
         """
 
         :param section: section
         :param name: value name
         :param value:  value
         :return: none
         """
         try:
             self.cf.add_section(section)
             self.cf.set(section, name, value)
             self.cf.write(open(filename, 'w'))
         except Exception :
             log.logger.exception('section %s has been exist!' %section)
             raise configparser.DuplicateSectionError(section)
         else:
             log.logger.info('write section'+section+'with value '+value+' successed!')
 
 if __name__ == '__main__':
     file_path = currPath
     print(file_path)
     read_config = DoConfIni()
 
     value = read_config.getConfValue(os.path.join(currPath,'config.ini'),'project','project_path')
     print(value)
 
     read_config.writeConfValue(os.path.join(currPath,'config.ini'),'tesesection', 'name', 'hello word')

4.2doexcel.py

'''
 Code description:read excel.xlsx, get values
 Create time:
 Developer:
 '''
 
 import xlrd
 import os
 import logging
 from retail.config import conf
 from retail.test_case.models.log import Logger
 
 log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
 
 class ReadExcel(object):
 
     def __init__(self,fileName='elementDate.xlsx',sheetName='elementsInfo'):
         """
 
         :param fileName:
         :param sheetName:
         """
         try:
             self.dataFile = os.path.join(conf.dataPath, fileName)
             self.workBook = xlrd.open_workbook(self.dataFile)
             self.sheetName = self.workBook.sheet_by_name(sheetName)
         except Exception:
             log.logger.exception('init class ReadExcel fail', exc_info=True)
             raise
         else:
             log.logger.info('initing class ReadExcel')
     # 读excel中的数据
     def readExcel(self,rownum,colnum):
         """
 
         :param rownum:
         :param colnum:
         :return:
         """
         try:
             value = self.sheetName.cell(rownum,colnum).value
         except Exception:
             log.logger.exception('read value from excel file fail', exc_info=True)
             raise
         else:
             log.logger.info('reading value [%s] from excel file [%s] completed' %(value, self.dataFile))
             return value
 
 if __name__ == '__main__':
     cellValue = ReadExcel().readExcel(1,3)
     print((cellValue))

4.3log.py

'''
 Code description:log info
 Create time:
 Developer:
 '''
 
 import logging
 import time
 
 class Logger(object):
     def __init__(self, logger, CmdLevel=logging.INFO, FileLevel=logging.INFO):
         """
 
         :param logger:
         :param CmdLevel:
         :param FileLevel:
         """
         self.logger = logging.getLogger(logger)
         self.logger.setLevel(logging.DEBUG)  # 设置日志输出的默认级别
         # 日志输出格式
         fmt = logging.Formatter('%(asctime)s - %(filename)s:[%(lineno)s] - [%(levelname)s] - %(message)s')
         # 日志文件名称
         # self.LogFileName = os.path.join(conf.log_path, "0.log".format(time.strftime("%Y-%m-%d")))# %H_%M_%S
         currTime = time.strftime("%Y-%m-%d")
         self.LogFileName = r'D:\\Petrochina_Retail_Test_Project\\retail\\report\\Log\\log'+currTime+'.log'
         # 设置控制台输出
         # sh = logging.StreamHandler()
         # sh.setFormatter(fmt)
         # sh.setLevel(CmdLevel)# 日志级别
 
         # 设置文件输出
         fh = logging.FileHandler(self.LogFileName)
         fh.setFormatter(fmt)
         fh.setLevel(FileLevel)# 日志级别
 
         # self.logger.addHandler(sh)
         self.logger.addHandler(fh)
 
     # def debug(self, message):
     #     """
     #
     #     :param message:
     #     :return:
     #     """
     #     self.logger.debug(message)
     #
     # def info(self,message):
     #     """
     #
     #     :param message:
     #     :return:
     #     """
     #     self.logger.info(message)
     #
     # def warn(self,message):
     #     """
     #
     #     :param message:
     #     :return:
     #     """
     #     self.logger.warning(message)
     #
     # def error(self,message):
     #     """
     #
     #     :param message:
     #     :return:
     #     """
     #     self.logger.error(message)
     #
     # def criti(self,message):
     #     """
     #
     #     :param message:
     #     :return:
     #     """
     #     self.logger.critical(message)
 
 if __name__ == '__main__':
     logger = Logger("fox",CmdLevel=logging.DEBUG, FileLevel=logging.DEBUG)
     logger.logger.debug("debug")
     logger.logger.log(logging.ERROR,'%(module)s %(info)s','module':'log日志','info':'error') #ERROR,log日志 error

4.4sendmail.py

'''
 Code description:send email
 Create time:
 Developer:
 '''
 
 import smtplib
 from email.mime.text import MIMEText
 from email.header import Header
 import os
 from retail.config import conf
 from retail.test_case.models.log import Logger
 
 log = Logger(__name__)
 #   邮件发送接口
 class SendMail(object):
     '''
     邮件配置信息
     '''
     def __init__(self,
                  receiver,
                  subject='Retail 系统测试报告',
                  server='smtp.qq.com',
                  fromuser='281754043@qq.com',
                  frompassword='gifhhsbgqyovbhhc',
                  sender='281754043@qq.com'):
         """
 
         :param receiver:
         :param subject:
         :param server:
         :param fromuser:
         :param frompassword:
         :param sender:
         """
 
         self._server = server
         self._fromuser = fromuser
         self._frompassword = frompassword
         self._sender = sender
         self._receiver = receiver
         self._subject = subject
 
     def sendEmail(self, fileName):
         """
 
         :param filename:
         :return:
         """
         #   打开报告文件读取文件内容
         try:
             f = open(os.path.join(conf.reportPath, fileName), 'rb')
             fileMsg = f.read()
         except Exception:
             log.logger.exception('open or read file [%s] failed,No such file or directory: %s' %(fileName, conf.reportPath))
             log.logger.info('open and read file [%s] successed!' %fileName)
         else:
             f.close()
             #   邮件主题
             subject = 'Python test report' #
             #   邮件设置
             msg = MIMEText(fileMsg, 'html', 'utf-8')
             msg['subject'] = Header(subject, 'utf-8')
             msg['from'] = self._sender
         #   连接服务器,登录服务器,发送邮件
             try:
                 smtp = smtplib.SMTP()
                 smtp.connect(self._server)
                 smtp.login(self._fromuser, self._frompassword)
             except Exception:
                 log.logger.exception('connect [%s] server failed or username and password incorrect!' %smtp)
             else:
                 log.logger.info('email server [%s] login success!' %smtp)
                 try:
                     smtp.sendmail(self._sender, self._receiver, msg.as_string())
                 except Exception:
                     log.logger.exception('send email failed!')
                 else:
                     log.logger.info('send email successed!')
 
 #   从文件中读取邮件接收人信息
 def getReceiverInfo(fileName):
     '''
     :param filename: 读取接收邮件人信息
     :return: 接收邮件人信息
     '''
     try:
         openFile = open(os.path.join(conf.dataPath, fileName))
     except Exception:
         log.logger.exception('open or read file [%s] failed,No such file or directory: %s' %(fileName, conf.dataPath))
     else:
         log.logger.info('open file [%s] successed!' %fileName)
         for line in openFile:
             msg = [i.strip() for i in line.split(',')]
             log.logger.info('reading [%s] and got receiver value is [%s]' %(fileName, msg))
             return msg
 
 if __name__ == '__main__':
     readMsg=getReceiverInfo('mail_receiver.txt')
     sendmail = SendMail(readMsg)
     sendmail.sendEmail('2021-04-21 17_44_04.html')

4.5strhandle.py

'''
 Code description: string handle
 Create time:
 Developer:
 '''
 
 import logging
 from retail.test_case.models.log import Logger
 
 log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
 def strhandle(str):
     """
 
     :param str:
     :return:
     """
     #初始化字符、数字、空格、特殊字符的计数
     try:
         lowerCase = 0
         upperCase = 0
         number = 0
         other = 0
         for stritem in str:
          #如果在字符串中有小写字母,那么小写字母的数量+1
             if stritem.islower():
                 lowerCase += 1
             #如果在字符串中有数字,那么数字的数量+1
             elif stritem.isdigit():
                 number += 1
             elif stritem.isupper():# 大写字母
                 upperCase +=1
             #如果在字符串中有空格,那么空格的数量+1
             else:
                 other += 1
         return lowerCase, upperCase, number, other
     except Exception as e:
         log.logger.exception('string handle error , please check!', exc_info=True)
         raise e
 
 if __name__=='__main__':
     list = ['qwert','erwer']
     lowercase, uppercase, number, other = strhandle(list[0])
     print ("该字符串中的小写字母有:%d" %lowercase)
     print ("该字符串中的大写写字母有:%d" %uppercase)
     print ("该字符串中的数字有:%d" %number)
     print ("该字符串中的特殊字符有:%d" %other)

4.6testreport.py

'''
 Code description:test report
 Create time:
 Developer:
 '''
 
 import time
 import logging
 import unittest
 from BeautifulReport import BeautifulReport
 import HTMLTestRunner
 from retail.config import conf
 from retail.test_case.models.log import Logger
 
 log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
 # 用HTMLTestRunner 实现的测试报告
 def testreport():
     """
 
     :return:
     """
     currTime = time.strftime('%Y-%m-%d %H_%M_%S')
     fileName = conf.reportPath + r'\\report' + currTime + '.html'
     try:
         fp = open(fileName, 'wb')
     except Exception :
         log.logger.exception('[%s] open error cause Failed to generate test report' %fileName)
     else:
         runner = HTMLTestRunner.HTMLTestRunner\\
             (stream=fp, title='Retail sys测试报告',
                                                description='处理器:Intel(R) Core(TM) '
                                                            'i5-6200U CPU @ 2030GHz 2.40 GHz '
                                                 '内存:8G 系统类型: 64位 版本: windows 10 家庭中文版')
         log.logger.info('successed to generate test report [%s]' %fileName)
         return runner, fp, fileName
 #
 def addTc(TCpath = conf.tcPath, rule = '*TC.py'):
     """
 
     :param TCpath: 测试用例存放路径
     :param rule: 匹配的测试用例文件
     :return:  测试套件
     """
     discover = unittest.defaultTestLoader.discover(TCpath, rule)
 
     return discover
 # 用BeautifulReport模块实现测试报告
 def runTc(discover):
     """
 
     :param discover: 测试套件
     :return:
     """
     currTime = time.strftime('%Y-%m-%d %H_%M_%S')
     fileName = currTime+'.html'
     try:
         result = BeautifulReport(discover)
         result.report(filename=fileName, description='测试报告', log_path=conf.reportPath)
     except Exception:
         log.logger.exception('Failed to generate test report', exc_info=True)
     else:
         log.logger.info('successed to generate test report [%s]' % fileName)
         return fileName
 
 if __name__ == '__main__':
     testreport()
     suite = addTc(rule = '*TC.py')
     runTc(suite)

4.7driver.py

以上是关于selenium UI自动化实战的主要内容,如果未能解决你的问题,请参考以下文章

Selenium系列(十四) - Web UI 自动化基础实战

Selenium系列(十五) - Web UI 自动化基础实战

selenium UI自动化实战

曲鸟全栈UI自动化教学:开始实战吧!实战环境准备

Selenium3与Python3实战 Web自动化测试框架

UI自动化测试养成记