前言:

 

      设计执行格式,封装PO模型工厂,实现PO模型脱离代码,一套代码执行所有项目的UI自动化,让UI自动化框架脱离高成本、低效率时代,将用例的重用性贯彻到极致,让烦人的PO模型变得无所谓,让一个测试小白都能编写并实现自动化

知识储备前提:熟悉python语言理论与实际运用,熟悉selenium库与自动化测试环境配置。对PO模型很熟悉。

《Python+Selenium WebUI自动化框架 -- 统一入口自动化》:Python+Selenium WebUI自动化框架 -- 统一入口自动化_ 

这一篇算是我所有文章最长的一篇了,也是最核心的了,掌握了,写一套自动化框架,执行所有项目UI自动化,不需要再动代码。

1、读取用例及设计用例格式

#[{"a": [{"A": 2}, {"A": 2}, {"A": 2}, {"A": 2}, {"A": 2}, {"A": 2}, {"A": 2}, {"A": 2}, {"A": 2}]},{"a": [5, 3, 2]}, {"a": [10, 4, 6]}]

用例一般使用excel通过一定逻辑写出来,然后通过代码读取后转换成一个格式化的数据集。

格式正解:

一整个excel文件存放在列表里

列表里有很多字典,每一个字典是一个sheet页,字典的key是sheet页标题,字典的value是sheet页里的内容

sheet页的内容又是一个列表,里面有着很多字典,每一个字典代表着一条用例

读取用例格式化的代码如下

def readallcase(self):     此方法遍历excel文件中的所有sheet页def readcase(self, sh):    此方法遍历sheet页中所有的row,将其组合成一条条用例case

class ReadCase(object):
    def __init__(self):
        self.sw = openpyxl.load_workbook(file)
        print(self.sw)


    def openxlsx(self, file):
        """
        打开文件
        :param dir:
        :return:
        """
        # self.sw = openpyxl.load_workbook(file)

    #[{"a": [{"A": 2}, {"A": 2}, {"A": 2}, {"A": 2}, {"A": 2}, {"A": 2}, {"A": 2}, {"A": 2}, {"A": 2}]},{"a": [5, 3, 2]}, {"a": [10, 4, 6]}]
    def readallcase(self):
        """
        取所有sheet页
        :return:list,返回sheet页里的数据
        """
        sheet_list = []
        for sh in self.sw:
            if 'common' != sh.title.split('_')[0] and 'common' != sh.title.split('-')[0] and sh.title[0] is not '#' :
                isOK, result = self.readcase(sh)
                if isOK:
                    sheet_list.append(result)
        if sheet_list is None:
            return False, '用例集是空的,请检查用例'
        return True, sheet_list


    def readcase(self, sh):
        """
        组合sheet页的数据
        :param sh:
        :return: list,返回组合数据
        """
        if sh is None:
            print('sheet页为空')
        datas = list(sh.rows)
        if datas == []:
            return False, '用例[' + sh.title + ']里面是空的'
        title = [i.value for i in datas[0]]
        rows = []
        sh_dict = {}
        for i in datas[1:]:
            data = [v.value for v in i]
            row = dict(zip(title, data))
            try:
                if str(row['id'])[0] is not '#':
                    row['sheet'] = sh.title
                    rows.append(row)
            except KeyError:
                raise e
                rows.append(row)
            sh_dict[sh.title] = rows
        return True, sh_dict

2、 实现不需要代码的PO模型

重点来了,这里应该会很难,首先说一个概念,“公共用例”,这应该是自动化界大多数人知道的。

公共用例的定义:可以是几个公共控件的操作,也可以是个登录首页,也可以是个中间过度页面,凡是多次用到的用例都可以写到公共用例里去,方便调用。

用了这种“公共用例” 代替PO模型。最开始我是在华为的自动化框架里见识这个概念,很强大,所以用自己的代码实现了并模仿了这个。

首先,我们设计一种用例规则,

‘调用用例’  四个字为可以调用执行其他sheet页用例的命令,然后设计能被调用sheet页标题为common_或common-开头 ,回顾上面的设计用例格式的代码 def readallcase(self):方法里有一行代码if 'common' != sh.title.split('_')[0] and 'common' != sh.title.split('-')[0] and sh.title[0] is not '#' :对,这行代码是在读取所有可执行用例时规避掉公共用例,因为公共用例是要在所有可执行用例里调用的,公共用例不能自己单独运行,

python 的 ui框架 python web ui框架_selenium

python 的 ui框架 python web ui框架_selenium_02

实现代码如下:

我们在工厂类里面定义两个方法

#初始化执行用例 def init_execute_case(self): 里面的内容:

一、读取了excel里所有可执行用例

二、调用用初始化公共用例

#初始化公共用例 def init_common_case(self, cases): 里面的内容:

一、判断是否有‘调用用例’命令,有则取公共用例合并成可执行用例

二、递归取公共用例里是否有‘调用用例’命令,有则继续取公共合并成可执行用例

注意:公共用例不能调用自已,递归死循环

from common.getconf import Config
from common.getcase import ReadCase
from basefactory.browseroperator import BrowserOperator
from basefactory.webdriveroperator import WebdriverOperator


class Factory(object):
     
    #初始化公共用例
    def init_common_case(self, cases):
        """
        :param kwargs:
        :return:
        """
        cases_len = len(cases)
        index = 0
        for case in cases:
            if case['keyword'] == '调用用例':
                xlsx = ReadCase()
                try:
                    case_name = case['locator']
                except KeyError:
                    return False, '调用用例没提供用例名,请检查用例'
                #取公共用例
                isOK, result = xlsx.get_common_case(case_name)
                if isOK and type([]) == type(result):
                    #递归检查公共用例里是否存在调用用例
                    isOK, result_1 = self.init_common_case(result)     
                elif not isOK:
                    return isOK, result
                list_rows = result[case_name]
                cases[index: index+1] = list_rows    #将公共用例插入到执行用例中去
            index += 1
        if cases_len == index:
            return False, ''
        return True, cases

   #初始化执行用例
    def init_execute_case(self):
        print("----------初始化用例----------")
        xlsx = ReadCase()
        isOK, result = xlsx.readallcase()
        if not isOK:
            print(result)
            print("----------结束执行----------")
            exit()
        all_cases = result
        excu_cases = []
        for cases_dict in all_cases:
            for key, cases in cases_dict.items():
                isOK, result = self.init_common_case(cases)    #将取的执行用例,去初始化一下公共用例   
                if isOK:
                    cases_dict[key] = result
                else:
                    cases_dict[key] = cases
                excu_cases.append(cases_dict)
                print("----------初始化用例完成----------")
        return excu_cases

然后在写好两个工厂方法后,我们还少了一个方法,那就是读取用例里的类里没有读取公共用例的方法,所以这里补上

这个方法在class ReadCase(object):读取用例的类下面,请回顾 1、读取用例及设计用例格式

def get_common_case(self, case_name):
        """
        得到公共用例
        :param case_name:
        :return:
        """
        try:
            sh = self.sw.get_sheet_by_name(case_name)
        except KeyError:
            return False, '未找到公共用例[' + case_name + '],请检查用例'
        except DeprecationWarning:
            pass
        return self.readcase(sh)

到这里这个框架所有的中心思想都出来了,希望大家能看懂。暂时没看懂的,拿着我这三篇文章,将里面的代码组合在一起,也能整出这个框架来。让我们一起学吧,谢谢

哦,把执行代码也放出来,因为是基础,所以不讲解了,基于unittest + ddt,详细请看下面代码:

用例执行类

import unittest
from common.factory import Factory
from library.ddt import ddt, data


@ddt
class Test_caserun(unittest.TestCase):
    fac = Factory()
    excu_cases = fac.init_execute_case()

    @data(*excu_cases)
    def test_run(self, acases):
        for key, cases in acases.items():
            for case in cases:
                isOK, result = self.fac.execute_keyword(keyword=case['keyword'],
                                                        type=case['type'],
                                                        locator=case['locator'],
                                                        index=case['index'],
                                                        input=case['input'],
                                                        check=case['check'],
                                                        time=case['time']
                )
                if isOK:
                    print(result)
                else:
                    raise Exception(result)

执行入口类

import os
import unittest
from library.HTMLTestRunnerNew import HTMLTestRunner
from common.getfiledir import CASEDIR, REPORTDIR


class Test_run(object):

    def __init__(self):
        self.suit = unittest.TestSuite()
        self.load = unittest.TestLoader()
        self.suit.addTest(self.load.discover(CASEDIR))
        self.runner = HTMLTestRunner(
            stream=open(os.path.join(REPORTDIR, 'report.html'), 'wb'),
            title='魂尾自动化工厂',
            description='唯a饭木领',
            tester='HUNWEI'
        )

    def excute(self):
        self.runner.run(self.suit)


if __name__=="__main__":
    test_run = Test_run()
    test_run.excute()

整个框架目录也奉上,这是最近写着玩的,所以发送邮件,打印日志什么的扩展,可以在common目录下自行添加

getconf.py与getfiledir.py中的一个是读配置文件,一个是读本框架所有目录,

python 的 ui框架 python web ui框架_测试工程师_03

最后看执行结果:

替代PO模型:一切公用的执行用例都可以放到以common开头的sheet页里,其他非common用例可以使用  调用用例 方法,在locator输入用例名可调用。细节处理(common用例可以调用common用例,但不可以调用自己,程序会死)

excel用例逻辑:

打开baidu,  等待页面出现,然后调用用例:common_input,  common_input的用例在第二张图,执行结果看第三图、四图

执行用例:

python 的 ui框架 python web ui框架_测试工程师_04

common公共用例:

python 的 ui框架 python web ui框架_selenium_05

执行页面:

python 的 ui框架 python web ui框架_selenium_06

执行步骤打印:

python 的 ui框架 python web ui框架_软件测试_07

结语:等手头上有空闲时间,自己再完善此框架,持续更新