美文网首页
自动化测试之数据驱动与关键字驱动

自动化测试之数据驱动与关键字驱动

作者: 羋学僧 | 来源:发表于2023-02-09 15:51 被阅读0次

    一、概述

    数据驱动的自动化测试

    从数据文件读取输入数据,通过变量的参数化,将测试数据传入测试脚本,不同的数据文件对应不同的测试用例。在这种模式下数据和脚本分离,脚本的利用率、可维护性大大提高,数据的覆盖率也较高,但受界面变化的影响仍然很大。

    关键字驱动的自动化测试

    关键字驱动测试是数据驱动测试的一种改进类型,它将测试逻辑按照关键字进行分解,形成数据文件,关键字对应封装的业务逻辑。

    主要关键字包括三类:被操作对象(Item)、操作(Operation)和值(value),依据不同对象还有其他对应参数。

    关键字驱动的主要思想是:脚本与数据分离、界面元素名与测试内部对象名分离、测试描述与具体实现细节分离。数据驱动的自动化测试框架在受界面影响方面,较数据驱动和录制/回放有明显的优势,可根据界面的变化更新对应的关键字对象,而不用重新录制脚本。

    二、 数据驱动模式—DDT

    1、核心原理

    程序不变,数据变

    即:多个测试用例的执行过程和操作一样的,只不过测试使用的数据和验证结果有所不同,数据驱动就是把测试数据与测试脚本进行分离,把数据放到配置文件中

    2、适用场景

    测试过程比较简单,但是需要使用大量的测试数据进行输入验证,适合个人测试

    3、ddt安装

    ddt是python的第三方库,安装用命令:pip install ddt 即可

    4、ddt模块

    ddt模块包含类的装饰器ddt和两个方法装饰器data

    • ddt.ddt:装饰类,也就是继承TestCase的类
    • ddt.data:装饰测试方法,参数是一系列的值
    • ddt.file_data:装饰测试方法,参数是文件名。文件可以是json或者yaml类型
      -- ① 如果文件是以“.yml”或者".yaml"结尾,ddt会作为yaml类型处理,其他文件都会作为json文件处理
      -- ② 如果文件是列表,列表的值会作为测试用例参数,同时,会作为测试用例方法名后缀显示
      -- ③ 如果文件是字典,字典的key会作为测试用例方法的后缀显示,字典的value会作为测试用例参数
    • ddt.unpack:传递的是复杂的数据结构时使用,比如使用列表或者元组,添加unpack后,ddt会自动把元组或者列表对应到多个参数上

    5、案例演示

    方式1:参数直接放在执行脚本文件里

    # 文件名:Internal_parameters_ddt.py
    import unittest
    import ddt
    from selenium import webdriver
    import time
    
    from selenium.webdriver.common.by import By
    
    
    @ddt.ddt
    class Praddt(unittest.TestCase):
        def setUp(self):
            self.driver = webdriver.Chrome()
    
        def tearDown(self):
            self.driver.quit()
    
        @ddt.data(
            ["数据驱动测试", "DDT"],
            ["关键字驱动测试", "51"],
            ["混合驱动测试", "python"]
        )
        @ddt.unpack
        def test_ddt(self, search_word, expect_word):
            self.driver.get('http://www.baidu.com')
            self.driver.find_element(By.ID,"kw").send_keys(search_word)
            self.driver.find_element(By.ID,"su").click()
            time.sleep(2)
            assert expect_word in self.driver.page_source
    
    if __name__ == '__main__':
        unittest.main()
    

    方式2:参数放在执行脚本外部数据文件里
    外部数据文件data.txt里面的数据如下:

    数据驱动测试;;;DDT
    关键字驱动测试;;;51
    混合驱动测试;;;python
    

    执行脚本文件代码如下:

    # 文件名:External_parameters_ddt.py
    from selenium import webdriver
    import time
    import sys
    
    # 读取data.txt文件
    from selenium.webdriver.common.by import By
    
    
    def get_test_datas(file_path):
        with open(file_path,encoding='utf-8') as fp:
            test_datas = fp.readlines()
        return test_datas
    
    # 获取数据文件中的search_word和expect_word
    test_datas = get_test_datas('data.txt')
    
    if len(test_datas) == 0:
        print('测试数据文件数据为空,请检查后再测试')
        sys.exit()
    
    # 每获取一组数据后,都执行下面的测试步骤
    for i in range(len(test_datas)):
        search_word,expect_word = test_datas[i].strip().split(';;;') # 去掉列表数据中的“\n”、“;;;”
        try:
            driver = webdriver.Chrome()
            driver.get('http://www.baidu.com')
            driver.find_element(By.ID,"kw").send_keys(search_word)
            driver.find_element(By.ID,"su").click()
            time.sleep(2)
            assert expect_word in driver.page_source
            driver.quit()
        except AssertionError:
            print('没有找到断言内容{}'.format(expect_word))
            driver.quit()
        except Exception as e:
            print('出现未知错误')
            driver.quit()
    

    二、关键字驱动模式—KDT

    1、核心原理

    把函数名称和程序进行分离
    关键字是指测试步骤中的某个动作,将其封装成函数的名称,即:把函数名放在配置文件中,然后从配置文件中读出函数名称以及函数对应的参数,组合成函数调用表达式来进行函数的调用

    测试步骤由:关键字、操作对象的定位表达式、操作值 三个部分组成。将这三个部分通过字符串拼接的方式,拼成一个函数的调用,以此来执行测试步骤的执行
    例如:
    测试步骤:在百度输入框输入“数据驱动测试”

    拼接调用:input||kw||数据驱动测试===>input(‘kw’,‘数据驱动测试’)

    2、适用场景

    可以在应用未提交测试之前,就可以建立关键字驱动测试用例对象库,适合大团队大项目里面实施,可以让不懂代码的测试人员也能做自动化测试。RobotFramework自动化测试框架采用的模式就是关键字驱动,常用于UI自动化测试。

    3、案例演示

    需求场景1:用谷歌浏览器打开百度,输入一个词进行搜索,再对搜索结果进行校验
    解决方案:将以上步骤用代码一一实现(面向过程)

    # 文件名:kdt_v1.py
    from selenium import webdriver
    import time
    
    from selenium.webdriver.common.by import By
    
    driver = webdriver.Chrome()
    driver.get('http://www.baidu.com')
    search_box = driver.find_element(By.ID,"kw")
    search_box.send_keys('数据驱动测试')
    submit_button = driver.find_element(By.ID,"kw")
    submit_button.click()
    time.sleep(2)
    assert 'DDT' in driver.page_source
    driver.quit()
    

    需求场景2:用谷歌浏览器打开百度,输入不同的词进行搜索,再对搜索结果进行一一校验,如果将以上操作步骤代码又重复写一遍的话,就会显得很繁琐了
    解决方案:将重复的操作步骤代码进行封装,直接通过txt文档写测试用例(面向对象)

    # 文件名:kdt_v2.py
    from selenium import webdriver
    import time
    
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.wait import WebDriverWait
    
    
    class KeyWord:
    
        _solit_chr = ";;;"
    
        def open_browser(self,browser_name):
    
            if 'chrome' in browser_name.lower():
                self.driver = webdriver.Chrome()
            elif 'ie' in browser_name.lower():
                self.driver = webdriver.Ie()
            else:
                self.driver = webdriver.Firefox()
            self.wait = WebDriverWait(self.driver, 10)
    
        def find_element(self, loc: str):
            value, *by = loc.split(self._solit_chr)
            if not by:
                by = By.XPATH
            else:
                by = getattr(By, by[0])
            ele = self.wait.until(lambda _: self.driver.find_element(by, value))
            return ele
    
        def visit(self,url):
            self.driver.get(url)
    
        def input(self,element,value):
            self.find_element(element).send_keys(value)
    
        def click(self,element):
            self.find_element(element).click()
    
        def sleep(self,seconds):
            time.sleep(int(seconds))
    
        def assertion(self,expect_word):
            assert expect_word in self.driver.page_source
    
        def quit(self):
            self.driver.quit()
    
    # 调试
    if __name__ == '__main__':
        kdt = KeyWord()
        kdt.open_browser('chrome')
        kdt.visit('http://www.baidu.com')
        kdt.input('kw;;;ID','数据驱动测试')
        kdt.click('su;;;ID')
        kdt.sleep(2)
        kdt.assertion('DDT')
        quit()
    

    修改后的代码看起来貌似是比前面的代码多了很多行,但是这里的核心思想是代码可以复用,具体怎么复用呢?此时我们需要新建一个测试用例文件test_steps.txt,里面内容如下:

    open_browser||chrome
    visit||https://www.baidu.com/
    input||kw;;;ID||数据驱动测试
    click||su;;;ID
    sleep||2
    assertion||DDT
    quit
    

    然后在封装的代码里面添加读取测试用例文件的函数,实现关键字驱动测试

    关键字驱动的核心是:将自然语言(如: open_browser||chrome) 转换成 (如:open_browser(“chrome”) )函数的调用

    具体函数的实现思路拆解:

    • ① 定义test_steps.txt,所有的测试步骤(关键字实现的)
    • ② 框架程序要读test_steps.txt,所有的行放到一个列表中,列表中的每一个元素是文件中的一行
      test_steps = [“open_browser||chrome\n”,“visit||https://www.baidu.com/\n”,…]
    • ③ 判断test_steps.txt列表中一共有多少元素,就知道有多少行,也就有多少个测试步骤
    • ④ 使用for循环,有多少个测试步骤,就循环多少次
    • ⑤ 使用strip去掉换行符\n,使用split做切割分别得到关键字和对应参数:

    【情况1】:
    有两个“||”,比如:“input||kw;;;ID||数据驱动测试\n”
    step = “input||kw||数据驱动测试\n”.strip().split("||")
    得到结果:[‘input’, ‘kw;;;ID’, ‘数据驱动测试’]
    keyword = step[0]
    element = step[1]
    value = setp[2]

    【情况2】:
    有一个“||”,比如:“open_browser||chrome\n”
    step = “open_browser||chrome\n”.strip().split("||")
    得到结果:[‘open_browser’, ‘chrome’]
    keyword = step[0]
    element = None
    value = setp[1]

    【情况3】:
    没有“||”,比如:“quit”
    keyword = step[0]

    • ⑥ 取到的几个值,最终要拼成一个函数调用的字符串:
      command = ‘open_browser(“chrome”)’
      command = ‘input(“kw;;;ID”,“数据驱动测试”)’
      command = ‘quit()’
    • ⑦ 用Python中的eval函数来调用字符串表达式
      eval(command)

    完整代码如下:

    # 文件名:kdt_v3.py
    import sys
    
    from selenium import webdriver
    import time
    
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.wait import WebDriverWait
    
    
    class KeyWord:
    
        _solit_chr = ";;;"
    
        def open_browser(self,browser_name):
    
            if 'chrome' in browser_name.lower():
                self.driver = webdriver.Chrome()
            elif 'ie' in browser_name.lower():
                self.driver = webdriver.Ie()
            else:
                self.driver = webdriver.Firefox()
            self.wait = WebDriverWait(self.driver, 10)
    
        def find_element(self, loc: str):
            value, *by = loc.split(self._solit_chr)
            if not by:
                by = By.XPATH
            else:
                by = getattr(By, by[0])
            ele = self.wait.until(lambda _: self.driver.find_element(by, value))
            return ele
    
        def visit(self,url):
            self.driver.get(url)
    
        def input(self,element,value):
            self.find_element(element).send_keys(value)
    
        def click(self,element):
            self.find_element(element).click()
    
        def sleep(self,seconds):
            time.sleep(int(seconds))
    
        def assertion(self,expect_word):
            assert expect_word in self.driver.page_source
    
        def quit(self):
            self.driver.quit()
    
    def get_test_steps_data(file_path):
        # 读取文件数据
        with open(file_path,encoding="utf-8-sig") as fp:
            test_datas = fp.readlines()
        return test_datas
    
    test_steps = get_test_steps_data('test_steps.txt')
    
    if len(test_steps) == 0:
        print('测试步骤文件的数据为空,请检查后再测试')
        sys.exit()
    
    kdt = KeyWord()
    # 读取的文件拼接成命令代码
    for i in test_steps:
        if i.count('||') == 2:
            keyword,element,value = i.strip().split('||')
            command = 'kdt.{0}("{1}","{2}")'.format(keyword,element,value)
        elif i.count('||') == 1:
            keyword,value = i.strip().split('||')
            command = 'kdt.{0}("{1}")'.format(keyword,value)
        elif i.count("||") == 0:
            keyword = i.strip()
            command = 'kdt.{}()'.format(keyword)
    
        try:
            # 通过eval()函数执行command的代码
            eval(command)
        except:
            flag = False
            print('{} 测试用例执行失败'.format(command))
        else:
            print('{} 测试用例执行成功'.format(command))
    

    三、混合模式驱动模式—HDT

    1、核心原理

    数据驱动+关键字驱动=混合驱动
    就是数据驱动和关键字驱动的联合,既用到数据驱动模式也用到关键字驱动模式

    2、适用场景

    需要实现:关键字(函数名)和程序分离、数据(包括函数需要的参数)和程序分离的场景
    测试人员只需在配置文件中维护好关键字和数据信息即可

    3、案例演示

    需求场景:用谷歌浏览器打开百度,输入不同的词进行搜索,再对搜索结果进行一一校验(测试数据和测试步骤都放在配置文件中)

    测试数据文件:test_datas.txt

    {"search_word":"数据驱动测试", "expect_word":"DDT"}
    {"search_word":"关键字驱动测试", "expect_word":"51"}
    {"search_word":"混合驱动测试", "expect_word":"python"}
    

    测试步骤文件:test_steps.txt

    open_browser||chrome
    visit||https://www.baidu.com/
    input||kw;;;ID||{{search_word}}
    click||su;;;ID
    sleep||2
    assertion||{{expect_word}}
    quit
    

    完整代码如下:

    # 文件名:hdt.py
    import os
    import re
    import sys
    
    from selenium import webdriver
    import time
    
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.wait import WebDriverWait
    
    
    class KeyWord:
    
        _solit_chr = ";;;"
    
        def open_browser(self,browser_name):
    
            if 'chrome' in browser_name.lower():
                self.driver = webdriver.Chrome()
            elif 'ie' in browser_name.lower():
                self.driver = webdriver.Ie()
            else:
                self.driver = webdriver.Firefox()
            self.wait = WebDriverWait(self.driver, 10)
    
        def find_element(self, loc: str):
            value, *by = loc.split(self._solit_chr)
            if not by:
                by = By.XPATH
            else:
                by = getattr(By, by[0])
            ele = self.wait.until(lambda _: self.driver.find_element(by, value))
            return ele
    
        def visit(self,url):
            self.driver.get(url)
    
        def input(self,element,value):
            self.find_element(element).send_keys(value)
    
        def click(self,element):
            self.find_element(element).click()
    
        def sleep(self,seconds):
            time.sleep(int(seconds))
    
        def assertion(self,expect_word):
            assert expect_word in self.driver.page_source
    
        def quit(self):
            self.driver.quit()
    
    
    # 读取测试数据
    def get_test_datas(test_data_file_path):
        if not os.path.exists(test_data_file_path):
            print('{}测试数据文件不存在,请确认!'.format(test_data_file_path))
            sys.exit(0)
        test_datas = []
        with open(test_data_file_path, encoding='utf-8-sig') as fp:
            for line in fp:
                test_datas.append(line.strip())
        return test_datas
    
    
    # 读取测试步骤
    def get_test_steps(test_steps_file_path):
        if not os.path.exists(test_steps_file_path):
            print('{}测试步骤文件不存在,请确认!'.format(test_steps_file_path))
            sys.exit(0)
        test_steps = []
        with open(test_steps_file_path, encoding='utf-8-sig') as fp:
            for line in fp:
                test_steps.append(line.strip())
        return test_steps
    
    
    test_datas = get_test_datas('test_datas.txt')
    
    kdt = KeyWord()
    
    # 有几行测试数据,就执行几次测试步骤
    for test_data in test_datas:
        '''{"search_word":"数据驱动测试", "expect_word":"ddt"} 是json串,把json串转换为字典类型'''
        test_data = eval(test_data)
        test_steps = get_test_steps('test_steps.txt')
        for test_step in test_steps:
            '''
            1)把test_step中{{xxx}}里面的xxx找出来,用正则:re.search(r"{{(.*?)}}")
            2)用test_data['xxx']把{{xxx}}替换掉
            '''
            if '{{' in test_step:
                key = re.search(r"{{(.*?)}}", test_step).group(1)
                test_step = re.sub(r"{{%s}}" % key, test_data[key], test_step)
            print(test_step)
    
            # 读取的测试步骤拼接成命令代码
            if test_step.count('||') == 2:
                keyword, element, value = test_step.strip().split('||')
                command = 'kdt.{0}("{1}","{2}")'.format(keyword, element, value)
            elif test_step.count('||') == 1:
                keyword, value = test_step.strip().split('||')
                command = 'kdt.{0}("{1}")'.format(keyword, value)
            elif test_step.count("||") == 0:
                keyword = test_step.strip()
                command = 'kdt.{}()'.format(keyword)
    
            try:
                '''通过eval()函数执行command的代码'''
                eval(command)
            except:
                flag = False
                print('{} 测试用例执行失败'.format(command))
            else:
                print('{} 测试用例执行成功'.format(command))
    
    

    相关文章

      网友评论

          本文标题:自动化测试之数据驱动与关键字驱动

          本文链接:https://www.haomeiwen.com/subject/bhickdtx.html