Python3+Selenium2完整的自动化测试实现之旅(七):完整的轻量级自动化框架实现

1、前言css

        前面系列Python3+Selenium2自动化系列博文,陆陆续续总结了自动化环境最基础环境的搭建、IE和Chrome浏览器驱动配置、selenium下的webdriver模块提供的元素定位和操做鼠标、键盘、警示框、浏览器cookie、多窗口切换等场景的方法、web自动化测试框架、python面向对象和POM设计模型以及python下的单元测试模块unittest模块。原本计划陆续按部就班的继续写一些篇章总结python面向对象编程、python下的logging日志模块、os.path路径处理模块、time模块处理时间,如格式化时间输出以及一些第三方模块如读取和向excel文件中写入数据的模块:xlrd和xlwt,写完这些后,再开始写本篇的终极目标:编写一个轻量级的自动化测试框架。最终放弃这样作,缘由:楼主发现python面向对象编程、python的这些标准库模块或者第三方模块其实不少博客已经作了很好的总结,总之,会学习的人,百度后总能从一大堆的文章中,查看并甄选出对本身解决问题或者思考有帮助和收获的文章,如百度python logging模块使用,多看博文就必定能找到对本身有帮助的文章。曾经楼主也是在学习实践中遇到不少坑,也是根据IDE输出上提示的错误本身先思考解决,仍是不行就百度一下或者看书,并深度学习下这块的内容,而后再去解决问题,从这些博文以及本身买的python类的书籍中也是受益良多,这也是楼主一直以来本身的学习方式。这里,每一个人都有本身的学习和思考问题的方式,找准适合本身的学习方式并执行它,完成一个阶段目标,而后设置下一个新目标,并为之努力。所以,在写这个轻量级的自动化web测试框架前,我跳过了上述诸多内容,包括且不限于:python面向对象编程、python经常使用标准库loggging、time、os.path运用等等,在后面的轻量级框架代码中会有部分注释,对于这些python相关的内容学习,你们根据本身的状况去充实,坚持学习并锲而不舍。在楼主身边,有太多相似的人学习老是三天晒鱼、两天打网的,彻底沉不下心来学习东西,浅尝辄止,没有积淀,若是认定一个东西就去想办法搞定,加油!楼主也在为本身新的目标fighting中,固然目标是广义的,能够是生活方面、工做方面、情感方面.......,好像跑偏题了O(∩_∩)O,这些人生鸡汤似的废话就不说了,看看下面这个web自动化测试框架是如何实现的吧~html

 二、项目架构说明python

       该项目架构基于楼主公司的一款B/S软件设计,你们也能够根据本身的被测软件来构建适合本身的架构层级,固然也能够参考楼主的。作自动化测试项目,当搞懂了思想和方法,其实都是万变不离其宗,就跟写代码同样,语言万千种,惟一不变的就是语言中异曲同工的思想,所以,玩会了套路天然就能凌驾于套路之上,运用并加入本身的东西。在PyCharm中新建以下的项目层级:
web

       有过开发经历的小伙伴都知道,有个好的交互式开发工具对于咱们建立和管理清晰的项目架构很方便,PyCharm就是一款交互良好的python开发工具。楼主上面的项目层级中部分目录和目录下的文件没展开,下面显示一个完整的目录结构,并说明每一个目录是用来干吗?放什么东西?编程

        固然这个项目层级设计,不是楼主一时间就固定下来的,也是在不断的摸索和采坑中,不断调整出的一个适合本身的框架目录层级。项目框架设计好了后,接下来就是慢慢补充内容一步步实现上面每一个目录须要的东西。来吧,开始造轮子~浏览器

 三、配置文件设计服务器

       首先,对于上面的config.ini的配置文件进行配置。说到配置文件,不论是开发人员仍是测试人员都不会陌生,还有xml、txt等格式的配置文件,配置文件就是用来配置一些参数和固定的变量值,通常是程序固定不变的东西咱们就放这里面,用于程序直接调用,若是修改配置文件中变量的值,程序调用该变量就会产生不一样的输出行为。如在作自动化测试时,咱们能够将测试的不一样浏览器写入到该文件中,当咱们须要调用firefox浏览器时,将参数设置成firefox便可,测试脚本将会在火狐浏览器进行。以下图,在配置文件中设置了浏览器参数、测试url、邮件服务器、邮件发送和接收者等参数。cookie

至于为何这个ini配置文件须要编辑成【###】而后下面是参数或者变量的赋值,本身百度学习:ini配置文件格式,看下是怎么编辑的?都有哪些要素?架构

、日志类模块的实现框架

       说到日志,你们都明白日志的做用,最明显的做用就是在程序的关键位置或者步骤节点下设置日志输出,当程序运行时,会输出日志,日志是咱们查看程序运行状况和查找错误的重要手段。所以,对于自动化测试也是如此,咱们须要知道自动化执行的状况以及执行错误的状况发生了什么,那就须要给你的自动化测试项目封装一个日志类的功能模块,用于输出日志。python语言封装了一个叫logging的标准库模块,可以设置日志等级以及怎么输出、输出到哪里。对于logging模块,你们能够本身针对性去学习该模块的使用。

       咱们在上面的项目层级的models目录下建立log.py文件,在这个模块文件下定义一个叫作Logger的日志类,完成日志类的封装,编辑以下代码:

'''
  Code description:封装日志类,定义日志文件输出格式和日志输出级别
  Create time:2018-11-8
  Developer:
'''
# -*- coding: utf-8 -*-
import logging
import time
import os.path
class Logger(object):
    def __init__(self,logger,CmdLevel = logging.INFO,FileLevel = logging.INFO):
        self.logger = logging.getLogger(logger)
        self.logger.setLevel(logging.DEBUG)   # 设置日志默认级别为DEBUG
        fmt = logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s - %(message)s') # 设置日志输出格式
        currTime = time.strftime('%Y%m%d%H%M',time.localtime(time.time()))  # 格式化当前时间
        log_path = os.path.dirname(os.path.abspath('E:\V2200_AutoTest\\testcase')) + '/log/logs/'  # 设置日志文件保存路径
        # log_path = os.path.dirname(os.path.abspath('.')) + '/log/logs/'      # 相对路径写法
        # print(os.path.dirname(os.path.abspath('E:\V2200_AutoTest\\testcase')))
        print('获得的日志路径为:', log_path)
        log_name = log_path + currTime + '.log'  # 设置日志文件名称

        # 设置由文件输出
        fh = logging.FileHandler(log_name,encoding='utf-8')  # 采用utf-8字符集格式防止出现中文乱码
        fh.setFormatter(fmt)
        fh.setLevel(FileLevel)  # 日志级别为INFO

        # 设置日志由控制台输出
        # sh = logging.StreamHandler(log_name)
        # sh.setFormatter(fmt)
        # sh.setLevel(CmdLevel)
        self.logger.addHandler(fh)  # 添加handler
    def getlog(self):
        return self.logger

     这样咱们就自定义封装了一个简单的日志类模块,设置了日志输出级别、输出格式以及输出日志的位置,后面其余模块须要输出日志时,就能够调用引入该日志类。

 五、浏览器模块的实现

     日志类实现简单封装后,继续造轮子~。此部分用于封装浏览器模块,主要实现打开和关闭不一样浏览器的方法,这里就用到了POM的思想,我们封装了浏览器的类型和打开关闭方法,那么后面每条测试脚本就能够直接调用打开和关闭浏览器方法,脚本只须要专一具体的测试业务逻辑的实现便可。在models目录下新建broser_engine.py文件,自定义一个叫作BrowserEngine类,实现浏览器模块的封装,代码以下:

'''
  Code description:封装浏览器引擎类,读取配置文件实现浏览器类型的选择,并封装打开浏览器和退出的方法
  Create time:2018-11-12
  Developer:
'''
# -*- coding: utf-8 -*-
import configparser          # python解析配置文件模块
import os.path
from selenium import webdriver
from V2200.test.models.log import Logger     # 引入日志类模块

logger = Logger(logger="BrowserEngine").getlog()    # 实例化对象logger

class BrowserEngine(object):
    def __init__(self, driver):
        self.driver = driver   # 初始化构造函数,将参数driver self化便于后面建立的方法直接自动调用
    def open_browser(self, driver):
        '''
        :param driver: 读取配置文件,返回driver
        :return:
        '''
        config = configparser.ConfigParser()
        file_path = os.path.abspath('E:\V2200_AutoTest\V2200\config\config.ini')   # 绝对路径写法
        #print('获得的读取config文件的路径:',file_path)
        config.read(file_path,encoding='UTF-8')    # 读取配置文件
        browser = config.get("browserType", "browserName")
        logger.info("选择的浏览器是: %s ." % browser)
        url = config.get("testServer", "URL")
        logger.info("测试的平台URL是: %s" % url)

        if browser == "Firefox":
            driver = webdriver.Firefox()
            logger.info("Starting firefox browser.")
        elif browser == "Chrome":
            driver = webdriver.Chrome()
            logger.info("Starting Chrome browser.")
        elif browser == "Ie":
            driver = webdriver.Ie()
            logger.info("Starting IE browser.")

        driver.get(url)                        # 获得测试的url
        logger.info("浏览器的版本为:%s" % driver.capabilities['version'])  # 获取浏览器版本
        driver.maximize_window()
        logger.info("最大化浏览器窗口.")
        driver.implicitly_wait(10)
        return driver

    def quit_browser(self):
        self.driver.quit()

 六、页面基类的实现

        此部分用于封装页面基类,主要用于封装一些经常使用的公共方法,如截图方法、元素定位方法、元素通用操做方法、警示框处理方法等等,只要软件页面一些经常使用的操做均可以写在该页面基类中,这个页面基础类就相似于一个公共函数库同样,封装这些方法,后面有须要的地方直接调用便可。以下代码,已经封装了8大元素定位方法、截图方法、鼠标点击方法、警示框处理方法等,后续根据本身的须要自行补充丰富一些经常使用的功能函数或者方法。这里能够着重看下8大元素定位方法的封装~

 

'''
  Code description:页面基类,封装全部页面共用的方法
  Create time:2018-11-13
  Developer:
'''
# -*- coding: utf-8 -*-
import time
import os.path
from V2200.test.models.log import Logger
from selenium.common.exceptions import NoSuchElementException    # selenium下封装的判断元素是否存在的模块
logger = Logger(logger='BasePage').getlog()
class BasePage(object):
    # 构造方法,初始化参数driver,用于后面的方法直接调用
    def __init__(self,driver):
        self.driver = driver
    # 浏览器前进
    def forward_browser(self):
        self.driver.forward()
        logger.info("在当前页面中点击浏览器前进.")
    # 浏览器后退
    def back_browser(self):
        self.driver.back()
        logger.info("在当前页面中点击浏览器后退.")
    # 设置隐式等待时间
    def wait(self,seconds):
        self.driver.implicitly_wait(seconds)
        logger.info("设置隐式时间:%d 秒." % seconds)
    # 关闭当前窗口
    def close_window(self):
        try:
            self.driver.close()
            logger.info("关闭当前窗口.")
        except NameError as e:
            logger.error("关闭当前窗口出错,抛出错误提示:%s." % e)
    # 截图功能:获得截图并保存图片到项目image目录下
    def get_window_img(self):
        file_path = os.path.dirname(os.path.abspath('.')) + '/image/'  # 设置存放截图的路径
        # print('截图保存路径为:%s' % file_path)
        timeset = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))       # 格式化时间
        pic_name = file_path + timeset + '.png'                                   # 定义截图文件名称
        try:
            self.driver.get_screenshot_as_file(pic_name)
            logger.info('截图成功,图片保存路径为:/image.')
        except Exception as e :
            logger.error('截图出现异常',format(e))
            self.get_window_img()

    # 8大页面元素(对象)定位方法的封装
    def find_element(self,selector):
        '''
        使用‘=>’做为字符串分割符,后续实际测试用例根据输入的元素selector_by和selector_value 进行选择元素的定位类型
        :param selector:
        :return: element
        '''
        element = ''
        if '=>' not in selector:
            return self.driver.find_element_by_id(selector)
        selector_by = selector.split('=>')[0]   # 按=>分割符进行切割字符串,返回一个列表,获得列表的第一个元素,即元素的定位方法
        selector_value = selector.split('=>')[1]  # 获得列表的第二个元素,即元素定位的值

        if selector_by == 'i' or selector_by == 'id':
            try:
                element = self.driver.find_element_by_id(selector_value)
                logger.info("定位元素OK,实际定位元素方法:%s ,定位的元素的属性值:%s" % (selector_by,selector_value))
            except NoSuchElementException as e:
                logger.error("没找到元素,抛出异常:%s" % e)
                self.get_window_img()  # 截取当前窗口
        elif selector_by == 'n' or selector_by == 'name':
            element = self.driver.find_element_by_name(selector_value)
        elif selector_by == 'c' or selector_by == 'class_name':
            element = self.driver.find_element_by_class_name(selector_value)
        elif selector_by == 'l' or selector_by == 'link_text':
            element = self.driver.find_element_by_link_text(selector_value)
        elif selector_by == 'p' or selector_by == 'partial_link_text':
            element = self.driver.find_element_by_partial_link_text(selector_value)
        elif selector_by == 't' or selector_by == 'tag_name':
            element = self.driver.find_element_by_tag_name(selector_value)
        elif selector_by == 'x' or selector_by == 'xpath':
            try:
                element = self.driver.find_element_by_xpath(selector_value)
                logger.info("定位元素OK,实际定位元素方法:%s ,定位的元素的属性值:%s" % (selector_by, selector_value))
            except NoSuchElementException as e:
                logger.error("没找到元素,抛出异常:%s" % e)
                self.get_window_img()  # 截取当前窗口
        elif selector_by == 'c' or selector_by == 'css_selector':
            element = self.driver.find_element_by_css_selector(selector_value)
        else:
            raise NameError("请输入正确的目标元素类型.")
        return element  # 返回变量element

    # 封装输入框方法
    def type(self,selector,text):
        el = self.find_element(selector)
        el.clear()
        try:
            el.send_keys(text)
            logger.info("输入的文本内容为:%s" % text)
        except NameError as e:
            logger.error("输入的内容异常,抛出异常:%s" % e)
            self.get_window_img()

    # 清除文本内容
    def clear(self,selector):
        el = self.find_element(selector)
        try:
            el.clear()
            logger.info("清除输入框文本信息OK")
        except NameError as e:
            logger.error("清除输入框内容失败:抛出异常: %s" % e)
            self.get_window_img()
    # 封装点击元素的动做
    def click(self,selector):
        el = self.find_element(selector)
        try:
            el.click()
            logger.info("点击元素动做完成")
        except NameError as e:
            logger.error("点击事件失败,抛出异常:%s" % e)
    # 获取打开的url地址标题
    def get_page_title(self):
        logger.info("当前打开的url地址标题为:%s" % self.driver.title)
        return self.driver.title

    # 获取警示框,并获得提示框信息和关闭提示框
    def get_alert(self):
        el = self.driver.switch_to.alert    # 获取窗口弹窗的方法
        try:
            assert '用户名或者密码错误' in el.text    # el.text方法获取提示框内容
            logger.info("弹窗提示正确")
            el.accept()                              # 点击弹窗确认按钮
        except Exception as e:
            print('弹窗提示错误', format(e))

    @staticmethod        #  静态方法:不强制要求传递参数,类能够不用实例化就能调用该方法
    def sleep(seconds):
        time.sleep(seconds)
        logger.info("等待时间是:%s 秒" % seconds)

 七、登录页面元素的封装

        在上面咱们实现了页面基类的封装,下图为楼主公司的一个软件登录页面,在page_obj目录下新建home_page.py实现这个登录页面元素定位和元素操做方法的封装

 

      代码以下:

'''
  Code description: 继承基类,封装登录页面全部的元素和元素的操做方法
  Create time:2018-11-16
  Developer:
'''
# -*- coding: utf-8 -*-
from V2200.test.models.base_page import BasePage
import xlrd                                    # excel操做相关的模块
from V2200.test.models.log import Logger
excelfile_path = 'E:\V2200_AutoTest\V2200\data\\testdata\elementData.xlsx'
workbook = xlrd.open_workbook(excelfile_path)
table_sheetName = workbook.sheet_by_name('登录页面业务组件')
logger = Logger(logger='HomePage').getlog()
class HomePage(BasePage):
    def __init__(self,driver):
        BasePage.__init__(self,driver)        # 继承父类,并调用父类的初始化方法
        self.input_username = table_sheetName.cell(1,1).value   # 读取excel表中用户名输入框元素
        self.input_password = table_sheetName.cell(2,1).value   # 读取excel表中密码输入元素
        self.rempwd = table_sheetName.cell(3,1).value           # 读取excel表中是否记住密码按钮元素
        self.loginBtn = table_sheetName.cell(4,1).value         # 读取excel表中登录按钮元素
        self.centerBtn = table_sheetName.cell(6,1).value        # 读取excel表中切换到中心用户的按钮
        logger.info("读取excel文件中登录页面相关元素数据完成")
    def center_user(self):
        self.click(self.centerBtn)
    def user(self,text):
        self.type(self.input_username,text)
    def pwd(self,text):
        self.type(self.input_password,text)
    def ifrempwd(self):
        self.click(self.rempwd)
    def login(self):
        self.click(self.loginBtn)

  这里引入了第三方的xlrd模块,用于读取excel文件中的数据,固然还有xlwt模块用于向excel写数据,说白了这两个模块就是实现操做excel,上面代码只用到了xlrd模块,在编写上面登录页面的封装前,我们先将登录页面定位的元素和元素属性写到对应的excel表中,这样作的好处就是实现测试数据和测试脚本的分离,若是页面元素发生变化,那么咱们就只须要修改excel中的元素属性而不须要修改代码,在data/testdata目录下新建名称为elementData.xlsx的文件,excel编辑内容以下:

    后续各个页面的元素都是定位以及元素的数据都是能够写在不一样的sheet中,至于xlrd模块具体向excel中读数据的方法以及使用,这里也是不作介绍,本身百度学习练习下就知道了。

软件其余页面的封装也是相似,按照上面的思想来就OK了。

 八、登录页面测试脚本的编写

    经过上面封装的基类和登录页面类,在unittest框架下开始编写具体的测试脚本。测试脚本在testcase下,如登录功能的脚本咱们写在:testcase/login_page_case目录下,其余页面的脚本写在对应的目录下。在testcase/login_page_case目录下建立:test_login_success.py和test_login_unsuccess.py分别表示登录成功的脚本和登录不成功的脚本。以下代码:

登录成功代码:

'''
  Code description:测试登录  Create time:2018-11-20  Developer:
'''
# -*- coding: utf-8 -*-
import unittest
# unittest执行测试用例,默认是根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。
import time
from V2200.test.models.browser_engine import BrowserEngine
from V2200.test.page_obj.home_page import HomePage
import xlrd
excelfile_path = 'E:\V2200_AutoTest\V2200\data\\testdata\elementData.xlsx'
workbook = xlrd.open_workbook(excelfile_path)
table_sheetName = workbook.sheet_by_name('登录页面业务组件')
class Login(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        # 测试前置条件
        browser = BrowserEngine(cls)
        cls.driver = browser.open_browser(cls)
    @classmethod
    def tearDownClass(cls):
        # 测试结束后环境的复原
        cls.driver.quit()
# case1:正确的用户密码登录
    def test_1_login_sucess(self):
        homepage = HomePage(self.driver)
        homepage.user(table_sheetName.cell(1,2).value)     # 读取excel中的数据
        homepage.pwd(table_sheetName.cell(2,2).value)
        homepage.ifrempwd()
        homepage.login()
        time.sleep(2)
        try:
            assert '视频监控' in homepage.get_page_title()
            print('test title success')
            homepage.get_window_img()  # 调用Basepage类封装的截图方法
        except Exception as e:
            print('test title error', format(e))

if  __name__  ==  '__main__':
    unittest.main()            # 将一个单元测试模块变成能够直接运行的测试脚本

  登录不成功代码:

'''
  Code description:测试登录  Create time:2018-11-20  Developer:
'''
# -*- coding: utf-8 -*-
import unittest
# unittest执行测试用例,默认是根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。
import time
from V2200.test.models.browser_engine import BrowserEngine
from V2200.test.page_obj.home_page import HomePage
import xlrd
# from V2200.test.page_obj.link_page import LinkPage
excelfile_path = 'E:\V2200_AutoTest\V2200\data\\testdata\elementData.xlsx'
workbook = xlrd.open_workbook(excelfile_path)
table_sheetName = workbook.sheet_by_name('登录页面业务组件')
class LoginUnsuccess(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        # 测试前置条件
        browser = BrowserEngine(cls)
        cls.driver = browser.open_browser(cls)
    @classmethod
    def tearDownClass(cls):
        # 测试结束后环境的复原
        cls.driver.quit()
# case2:错误的用户+正确的密码登录
    def test_2_login_erroruser(self):
        homepage = HomePage(self.driver)
        homepage.user(table_sheetName.cell(1, 3).value)     # 读取excel中的数据
        homepage.pwd(table_sheetName.cell(2, 3).value)
        homepage.ifrempwd()
        homepage.login()
        time.sleep(2)
        try:
            assert '视频监控' in homepage.get_page_title()
            print('test title success')
            homepage.get_window_img()  # 调用Basepage类封装的截图方法
        except Exception as e:
            print('test title error',format(e))

# case3:正确的用户+错误的密码登录
    def test_3_login_errorpasswd(self):
        homepage = HomePage(self.driver)
        homepage.user(table_sheetName.cell(1, 4).value)     # 读取excel中的数据
        homepage.pwd(table_sheetName.cell(2, 4).value)
        homepage.ifrempwd()
        homepage.login()
        time.sleep(2)
        try:
            assert '视频监控' in homepage.get_page_title()
            print('test title success')
            homepage.get_window_img()  # 调用Basepage类封装的截图方法
        except Exception as e:
            print('test title error', format(e))
# case4:错误的用户+错误的密码登录
    def test_4_login_erroruser_errorpasswd(self):
        homepage = HomePage(self.driver)
        homepage.user(table_sheetName.cell(1, 5).value)     # 读取excel中的数据
        homepage.pwd(table_sheetName.cell(2, 5).value)
        homepage.ifrempwd()
        homepage.login()
        time.sleep(2)
        try:
            assert '视频监控' in homepage.get_page_title()
            print('test title success')
            homepage.get_window_img()  # 调用Basepage类封装的截图方法
        except Exception as e:
            print('test title error', format(e))

if  __name__  ==  '__main__':
    unittest.main()            # 将一个单元测试模块变成能够直接运行的测试脚本

 九、测试执行控制模块

      完成上面的测试脚本编写后,对于自动化测试还须要有一个测试执行控制的部分,用来控制执行哪些用例集,生成HTML可视化的测试报告,并实现测试报告邮件发送。

在runtest目录下新建run_all_case.py,编辑以下代码:

'''
  Code description: TestLoader测试case,并执行获得的全部测试集,生成html文件的测试报告并邮件发送测试报告
  Create time:2018-11-20
  Developer:
'''
# -*- coding: utf-8 -*-
import HTMLTestRunner1     # 导入开源的测试报告生成HTML格式的模块
import os.path
import time
import unittest
import configparser        # 解析配置文件模块
from email.mime.text import MIMEText
from email.header import Header
import smtplib
"""
发邮件须要用到python两个模块,smtplib和email,这俩模块是python自带的,只需import便可使用。
smtplib模块主要负责发送邮件,email模块主要负责构造邮件。
其中MIMEText()定义邮件正文,Header()定义邮件标题。MIMEMulipart模块构造带附件

"""
# ===============定义邮件发送============
def send_mail(file_new):

    config = configparser.ConfigParser()
    file_path = os.path.dirname(os.path.abspath('.')) + '/V2200/config/config.ini'
    config.read(file_path, encoding='UTF-8')                 # 读取config配置文件
    emailserver = config.get("emailserver", "emailservice")
    from_user = config.get("emailfrom_user", "from_user")
    from_passwd = config.get("emailfrom_passwd", "from_passwd")
    to_user = config.get("emailto", "to_user")

    f = open(file_new,'rb')
    mail_boy = f.read()
    f.close()
    msg = MIMEText(mail_boy,'html','utf-8')        # 定义邮件正文
    msg['Subject'] = Header('V2200自动化测试报告','utf-8')  # 定义邮件标题
    smtp = smtplib.SMTP()
    smtp.connect(emailserver)                     #  链接邮箱服务器
    smtp.login(from_user,from_passwd)   #  邮件发送方登录
    smtp.sendmail(from_user,to_user,msg.as_string())  # 邮件发送者和接收者
    smtp.quit()
    print("邮件已经发送,请注意查收!")

# ==============找到最新生成的测试报告文件===========
def new_report(report_path):
    lists = os.listdir(report_path)   # 获得项目目录下全部的文件和文件夹
    lists.sort(key=lambda fn:os.path.getmtime(report_path + '\\' + fn))  # 将获得的文件和文件夹按建立时间排序
    file_new = os.path.join(report_path,lists[-1])  # 获取最新建立的文件
    print(file_new)
    return file_new
# 测试用例路径
# case_path = os.path.join(os.getcwd(),'testcase')
case_path = os.path.abspath('E:\V2200_AutoTest\\testcase')
print(case_path)
# 测试报告路径
report_path = os.path.abspath('E:\V2200_AutoTest\\testreport')
print(report_path)
def all_case():
    '''
    找到case_path路径下全部以test_login开头的测试用例文件,保证每一个子目录都是一个包文件,即该目录下
    有__init__.py文件,才能获取到多个目录下的全部test*.py的文件下的全部测试用例
    '''
    all_case = unittest.defaultTestLoader.discover(case_path,pattern="test_login*.py",top_level_dir=None)
    print(all_case)
    return all_case
if __name__ == '__main__':
    # 获取当前时间,并格式化时间
    now_time = time.strftime("%Y-%m-%d-%H_%M_%S",time.localtime(time.time()))
    # html测试报告路径
    report_html = os.path.join(report_path,"result_"+now_time+".html")
    fp = open(report_html,'wb')     # 打开一个文件,将测试结果写入该文件中
    '''
    wb:以二进制格式打开一个文件只用于写入。若是该文件已存在则打开文件,并从开头开始编辑,
    即原有内容会被删除。若是该文件不存在,建立新文件
    '''
    runner = HTMLTestRunner1.HTMLTestRunner(stream=fp,
                                           title=u'V2200自动化测试报告,测试结果以下:',
                                           description=u'用例执行状况:')

    runner.run(all_case())   # 执行全部测试case
    fp.close()
    mail_report = new_report(report_path)
    send_mail(mail_report)

  该代码,编写了怎么获取须要执行的测试用例脚本和引入生成可视化测试报告的模块和发送邮件模块等,对于这几个模块本身多学习下就能掌握。

、测试执行效果

    经过上面这些类的封装以及测试脚本的编写,算是完成了咱们自动化测试框架的基本具有的东西。忙活了这么久,是时候来看看我们的效果了。PyCharm中运行run_all_case.py,运行完成后的效果以下:

 我们再看看log/logs路径下生成的日志,就以下图这样:

 同时执行完成后,在testreport目录下会生成HTML格式的可视化测试报告文件,用浏览器打开效果以下:

 这报告是否是很酷炫啊,O(∩_∩)O哈哈~

     还有测试报告发送邮件给到指定的邮箱哦,若是你的自动化测试执行完了,能够把该自动化测试报告自动邮件发给你的leader,领导看到了是否是对你刮目相看?楼主上面的代码设置发送的是楼主公司内网使用的邮箱:foxmail,效果以下:

到这里算是完成了我们自动化测试框架,并取得了必定的成果~~

十一、整个自动化测试框架的总结和反思

        其实到第十节的介绍,楼主算是成功的作出了一个轻量级的测试框架,but,回过头来继续思考,仍是有诸多须要优化和待下一步解决的问题:

1.页面基类还须要补充更多的公共函数或者方法;

2.可视化HTML测试报告内容还不够丰富,没有完善的测试执行失败的用例的详细描述和测试截图附件显示;

3.整个框架的部分逻辑还须要优化和改进;

4.待解决的问题:没实现测试脚本的持续集成和定时执行,如今想到的是配合jenkins持续集成来达到自动构建测试执行任务;

5.想独立开发一个web测试平台,如今想到的是学习Django的web框架来开发一个自动化测试平台;

    对于这样不足和构想,楼主也是会继续学习相关的知识,并一步步实现它,对于看到该博客的朋友们也能够给楼主一些好的建议和指出错误,但愿有对自动化测试有兴趣的朋友,你们共同窗习和进步哦。

相关文章
相关标签/搜索