robotframework-自动化测试-实例8(数据驱动)

前情介绍:
在自动化测试框架中,数据驱动的意思是指定的是测试用例或者说测试套件是由外部数据集合来驱动的框架。

数据集合(也可称之为数据来源)可以是任何类型的数据文件比如xls,xlsx,csv等等,甚至可以是数据库中的表。总之,是一个放数据的地方就对了。

核心思想就是数据和测试代码分离,及时当测试数据发生大量变化的情况下测试代码(或者说测试用例)可以保持不变。

最常见的例子是需要用多个不同的账号和密码来登陆某个邮箱,来验证哪些是有效的值,哪些是错误的值,或者哪些值可以导致出错等等。

数据驱动并不是和关键字驱动等水火不相容的一种驱动模式,我的理解是,两者更像是互相协助的关系。甚至你把数据看成一种关键字也未尝不可。

练习环境配置
实例1(UI自动化-百度搜索)
实例2(有效登录)
实例3(无效登录)
实例4 (Appium)
实例5 (连接mysql数据库)
实例6 (GET/POST请求)
实例7(接口API测试)
Appium Error总结
robotframework Error总结

测试需求:
为了更纯粹一点的看到RF中的数据驱动的模式,这次采用了官方的Demo做一个讲解。
对 一个 简单计算器的Calculator.py进行测试,Calculator.py的代码如下(写的漂亮):

class Calculator(object):
    BUTTONS = '1234567890+-*/C='

    def __init__(self):
        self._expression = ''

    def push(self, button):
        if button not in self.BUTTONS:
            raise CalculationError("Invalid button '%s'." % button)
        if button == '=':
            self._expression = self._calculate(self._expression)
        elif button == 'C':
            self._expression = ''
        elif button == '/':
            self._expression += '//'    # Integer division also in Python 3
        else:
            self._expression += button
        return self._expression

    def _calculate(self, expression):
        try:
            return str(eval(expression))
        except SyntaxError:
            raise CalculationError('Invalid expression.')
        except ZeroDivisionError:
            raise CalculationError('Division by zero.')


class CalculationError(Exception):
    pass

测试设计:
数据驱动引入了一个非常有效的概念,即“模板”概念,在很多测试场景下,测试人员输入的操作是有一定重复性的,区别只在于输入的数据,还是以登陆为例,除了包含正常的测试用例,还需要有其他的异常用例覆盖才能保证登陆接口的正确性。基于横向构造不同的测试数据输入来判断不同的测试结果,即为数据驱动。行为可以封装成模板。

先用一个CalculatorLibrary库来进行封装需要做的测试步骤,对应的验证和错误处理

  • push button
  • push buttons
  • result_should_be
  • should_cause_error

再在RF中设计两个模板来使用上面库中的方法。

不同的输入数据则在测试用例中体现。

测试实现:
1 . 编写CalculatorLibrary.py文件,代码示例如下(最漂亮的还是写注释的地方,啧啧啧):

from calculator import Calculator, CalculationError


class CalculatorLibrary(object):
    """Test library for testing *Calculator* business logic.

    Interacts with the calculator directly using its ``push`` method.
    """

    def __init__(self):
        self._calc = Calculator()
        self._result = ''

    def push_button(self, button):
        """Pushes the specified ``button``.

        The given value is passed to the calculator directly. Valid buttons
        are everything that the calculator accepts.

        Examples:
        | Push Button | 1 |
        | Push Button | C |

        Use `Push Buttons` if you need to input longer expressions.
        """
        self._result = self._calc.push(button)

    def push_buttons(self, buttons):
        """Pushes the specified ``buttons``.

        Uses `Push Button` to push all the buttons that must be given as
        a single string. Possible spaces are ignored.

        Example:
        | Push Buttons | 1 + 2 = |
        """
        for button in buttons.replace(' ', ''):
            self.push_button(button)

    def result_should_be(self, expected):
        """Verifies that the current result is ``expected``.

        Example:
        | Push Buttons     | 1 + 2 = |
        | Result Should Be | 3       |
        """
        if self._result != expected:
            raise AssertionError('%s != %s' % (self._result, expected))

    def should_cause_error(self, expression):
        """Verifies that calculating the given ``expression`` causes an error.

        The error message is returned and can be verified using, for example,
        `Should Be Equal` or other keywords in `BuiltIn` library.

        Examples:
        | Should Cause Error | invalid            |                   |
        | ${error} =         | Should Cause Error | 1 / 0             |
        | Should Be Equal    | ${error}           | Division by zero. |
        """
        try:
            self.push_buttons(expression)
        except CalculationError as err:
            return str(err)
        else:
            raise AssertionError("'%s' should have caused an error."
                                 % expression)

2 . RF中创建一个Data Driven的项目,测试用例和模板的名字的结构如下:

10.jpg

在项目那一级导入CalculatorLibrary库,导入后CalculatorLibrary里的方法都可以被作为关键字使用。

  • 将刚才的CalculatorLibrary.py文件放在和这个项目同一个目录下。
  • 点击Library按钮后输入文件名即可导入。
11.jpg

3 . 最下方的两个齿轮形状的就是模板形式,可以通过New User Keyword的方式来创建(创建好一个项目后,在项目名上右键则可创建User Keyword),对于计算器测试来说,也就两种结果,一种是输入正常的值得到正常的结果,一种是输入异常的值得到错误提示
Calculator - 正常的值的测试步骤

Calculator.jpg

Calculator should fail-异常的值的测试步骤

should fail.jpg

4 .构造测试用例来进行测试。
加减乘除,输入异常,输入不允许的值(一串字符串,空值,除以0),比如:

Calculator error.jpg

最终代码如下:

*** Settings ***
Documentation     Example test cases using the data-driven testing approach.
...
...               The _data-driven_ style works well when you need to repeat
...               the same workflow multiple times.
...
...               Tests use ``Calculate`` keyword created in this file, that in
...               turn uses keywords in ``CalculatorLibrary.py``. An exception
...               is the last test that has a custom _template keyword_.
...
...               Notice that one of these tests fails on purpose to show how
...               failures look like.
Test Template     Calculate
Library           CalculatorLibrary.py

*** Test Cases ***    Expression    Expected
Addition              12 + 2 + 2    16
                      2 + -3        -1

Subtraction           12 - 2 - 2    8
                      2 - -3        5

Multiplication        12 * 2 * 2    48
                      2 * -3        -6

Division              12 / 2 / 2    3
                      2 / -3        -1

Failing               1 + 1         3

Calculation error     [Template]    Calculation should fail
                      kekkonen      Invalid button 'k'.
                      ${EMPTY}      Invalid expression.
                      1 / 0         Division by zero.

*** Keywords ***
Calculate
    [Arguments]    ${expression}    ${expected}
    Push buttons    C${expression}=
    Result should be    ${expected}

Calculation should fail
    [Arguments]    ${expression}    ${expected}
    ${error} =    Should cause error    C${expression}=
    Should be equal    ${expected}    ${error}    # Using `BuiltIn` keyword

CC先生说:RF的数据驱动看起来的确是非常简洁的,采用了封装的思维,将更多的操作都封装到库,模板中,干净利落的实现了测试数据和测试步骤的分离。大热天的,看起来还真是清爽~~~

干净 利落
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容