Lettuce(基于Python的BDD工具,中文编写自动化测试用例)

小编使用Lettuce、PO(非PO)模式写的UI自动化测试框架可供参考地址
https://github.com/Mrfenghaha/DemoUITestLettuce

一、Lettuce介绍

1.1 BDD

了解lettuce需要先了解BDD,BDD是TDD的一种衍生,通过特定的BDD框架,用自然语言或类自然语言,按照编写用户故事或者用户用例的方式,以功能使用者的视角,描述并编写测试用例。

BDD源于TDD并优于测试驱动开发。

之所以说BDD优于测试驱动开发,并非空穴来风,主要原因如下:

  1. 更加以人为本:TDD更多关注于测试接口实现逻辑正确性,而BDD重点关注用户使用功能时的行为和结果是否与符合预期。
  2. 更加以人为本:TDD基本上是使用编程语言来描述测试用例,而BDD则是用自然语言来描述测试用例。
  3. 更加以人为本:TDD不关注客户价值,而BDD从客户价值开始书写
  4. 更加以人为本:TDD的需求文档和测试用例是分别存储的,而BDD的需求文档就是测试用例
  5. 更加以人为本:TDD要求所有被覆盖的接口都要进行良好重构,而BDD只要求对暴露给客户使用的接口甚至UI具有可测试性
  6. 更加以人为本:TDD更多是团队纪律或者领导推动的,而BDD是客户需求拉动的

1.2 Lettuce

学习BDD(行为驱动开发),业界流行的BDD框架是Ruby语言编写的Cumumber,不过对于用Python习惯的朋友可以学习一下Cumumber在Python下的衍生品-Lettuce。

lettuce 除了官方文档外,几乎找不到其它资料,为了理解lettuce,我们不妨多去看看cucumber 的资料。对于项目的自动化测试,它可以执行纯文本的功能描述,它允许我们用自然语言去描述个一个系统的行为。

可以学习别人分享的官网文档翻译博客
在这里插入图片描述

二、Lettuce安装

2.1 Python2

命令行安装(当前的lettuce0.2.x版本仍然只支持python2)

pip install Lettuce

2.2 Python3

  • 方式一
    因为lettuce目前只支持python2,python3需要自行下载安装。Github有大佬更新的0.2.23最新版本
    https://github.com/sgpy/lettuce/tree/py3
git clone https://github.com/sgpy/lettuce.git  # clone大佬源码在任意位置
cd lettuce  # 进入源码项目
git checkout -b py3 origin/py3  # 创建python3分支并clone
sudo python3 setup.py install  # 安装支持python3的版本替换原lettuce
lettuce --version  # 检查版本号看是否安装成功

此方法是直接安装lettuce但是需要加sudo授权

  • 方式二(使用旧版本替换)
    Github有大佬更新的0.2.10版本
    https://github.com/e0ne/lettuce/tree/python3
pip3 install lettuce  # 安装lettuce
git clone https://github.com/e0ne/lettuce.git  # clone大佬源码在任意位置
cd lettuce  # 进入源码项目
git checkout -b python3 origin/python3  # 创建python3分支并clone
python3 setup.py install --record logName  # 安装支持python3的版本替换原lettuce,并且将文件路径记录下载方便卸载删除
lettuce -V  # 检查版本号是否安装成功

此方法只是替换了lettuce的访问路径,调用的时候路径发生变化,但是pip3安装的版本仍在

2.3 卸载

python2 直接卸载即可

pip uninstall lettuce

python3方式一直接卸载即可

sudo pip3 uninstall lettuce  # 需要加sudo因为安装极为sudo权限

python3 方式二卸载麻烦一些

pip3 uninstall lettuce  # 卸载pip安装的lettuce版本

cd lettuce
cat logName | xargs rm -rf  # 根据安装的log路径删除替换版本相关文件,这种方法可能删除的不干净
or
sudo rm -rf /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/lettuce/  # 直接删除整个文件
sudo rm -rf /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/lettuce-0.2.23-py3.7.egg-info  # 删除信息文件

三、Lettuce使用

3.1 项目文件结构介绍

|-- features      # lettuce 会根据目录路径查找相关文件
|    -- xxxx.feature  # BDD 的描述文件
|    -- xxxx.py  # 相关的python方法脚本

可以根据自己的需要在features下再创建文件夹用于分类等,lettuce会自动读取featuress文件下所有文件

3.2 使用介绍

3.2.1 样例

sample.feature

Feature: Compute factorial
  In order to play with Lettuce
  As beginners
  We'll implement factorial

  Scenario: Factorial of 0
    Given I have the number 0
    When I compute its factorial
    Then I see the number 1

sample.py

# -*- coding:utf-8 -
from lettuce import *


def factorial(number):
    return 1


@step('I have the number (\d+)')
def have_the_number(step, number):
    world.number = int(number)


@step('I compute its factorial')
def compute_its_factorial(step):
    world.number = factorial(world.number)


@step('I see the number (\d+)')
def check_number(step, expected):
    expected = int(expected)
    assert world.number == expected, "Got %d" % world.number

3.2.2 描述文件

lettuce规定了一系列的语法,你按照它的规则 告诉它,它就可以理解你的需求。feture文件中的关键字的作用和单元测试中的关键字的对应关系如下:
在这里插入图片描述

3.2.3 world

为了更容易和更有趣的编写测试,Lettuce”违背了“python中好的设计的一些原则,如避免隐含的利用全局概念。

Lettuce的“world”概念主要是“全局的概念”。例如下面UI自动化测试的例子,启动浏览器将driver写入world中,后续的调用直接引用world.driver即可。

3.2.4 脚本文件

steps里面都是使用@step这个注解来表示你要做的行为对应的代码实现。

对于内容替换则按照正则表达式的方式,将函数所需的参数直接按照顺序提取出来

3.2.5 执行

直接在根目录下执行lettuce即可,即features上一层文件夹执行

lettuce  # 执行所有的测试用例
lettuce /xx/xx/xx/xxx.feature  # 执行指定文件,这种方式可以不将features用例文件放在features文件下

3.2.6 结果在这里插入图片描述

3.3 进行接口测试

interface.feature

Feature: Interface Learning
  In order to play with Lettuce
  As beginners

  Scenario: Test Interface
    Given I have the parm 10 and 0
    When I to calling interface
    Then I see the state of response is 200
    Then I see the success of response is "true"

interface.py

# -*- coding:utf-8 -
import json
import requests
from lettuce import *


# string类型转布尔值类型
def str_to_boolean(value):
    return value == 'true'


def mock_show_lists(page_num, num):
    request = {
        "url": 'http://localhost:5000/mock_server/mock/show_lists',
        "method": "post",
        "headers": {"content-type": "application/json"},
        "data": {"page_num": page_num, "num": num}
    }
    return requests.post(url=request['url'], data=json.dumps(request['data']), headers=request['headers'])


@step('I have the parm (\d+) and (\d+)')
def have_the_parm(step, page_num, num):
    world.number = int(page_num)
    world.num = int(num)


@step('I to calling interface')
def calling_interface(step):
    world.result = mock_show_lists(world.number, world.num)


@step('I see the state of response is (\d+)')
def check_number(step, status):
    world.status = int(status)
    assert world.result.status_code == world.status


@step('I see the success of response is "(.*?)"')
def check_number(step, success):
    world.success = str_to_boolean(success)
    assert world.result.json()['success'] == world.success

3.4 进行UI测试

testui.feature

Feature: Lettuce Learning
  In order to play with Lettuce
  As beginners

  Scenario: Test Interface
    Given I open the browser
    When I Access to web sites "https://www.amazon.cn/"
    Then I enter "toothbrush" in the search input box
    Then I hit the search button
    Then I close the browser

testui.py

# -*- coding:utf-8 -
from lettuce import *
from selenium import webdriver
from selenium.webdriver.common.by import By


@step('I open the browser')
def get_driver(step):
    world.driver = webdriver.Chrome()
    # 将浏览器窗口最大化
    world.driver.maximize_window()
    world.driver.implicitly_wait(5)
    # return driver


@step('I Access to web sites "(.*?)"')
def visit_website(step, url):
    # world.driver = get_driver()
    world.driver.get(url)


@step('enter "(.*?)" in the search input box')
def send_search_action(step, text):
    search_type = (By.ID, 'twotabsearchtextbox')
    world.driver.find_element(*search_type).send_keys(text)


@step('I hit the search button')
def click_submit_action(step):
    submit_type = (By.XPATH, '//*[@id="nav-search"]/form/div[2]/div/input')
    world.driver.find_element(*submit_type).click()


@step('I close the browser')
def close(step):
    world.driver.quit()

3.5 设置语言

Lettuce目前支持18种语言:
英语、葡萄牙(Português)、波兰(Polski)、加泰罗尼亚(Català)、西班牙(Español)、匈牙利(Magyar)、法国(Français)、德语(Deutsch)、日本(日本語)、土耳其(Türkçe)、简体中文(简体中文)、繁体中文(繁體中文)、俄罗斯(Русский)、乌克兰(Українська)、意大利(Italiano)、挪威(Norsk)、瑞典(Svenska)、捷克(Čeština)

具体的写法语言请参考源码,查看如图位置language .py文件即可

cat lettuce/lettuce/languages.py 

在这里插入图片描述
设置为中文,只需要在每个features文件前加上# language: zh-CN,对应的step中的描述换为中文即可,例如下:

# language: zh-CN

特性: UI自动化测试模版

  场景: 亚马逊商城搜索商品并加入购物车,检验是否添加成功以及金额
    Given 我打开谷歌浏览器
    And 我访问亚马逊首页
    When 我在首页,搜索商品"牙刷"
    And 我在商品搜索列表页,点击商品"惠百施 熊本熊 成人牙刷 (颜色随机)"
    And 我切换到浏览器第2个页签
    And 我在商品详情页,点击加入购物车按钮
    And 我在商品加入购物车成功页面,获取成功文本
    And 我比较文本与"商品已加入购物车"是否相等
    And 我在商品加入购物车成功页面,获取金额文本
    And 我比较文本与"¥ 81.88"是否相等
    Then 我关闭浏览器或设备

3.6 持续集成Jenkins

集成Jenkins也很简单,只需要创建一个任务添加构建Execute shell即可,写入如下:

#!/bin/bash -ilex  # 说明使用系统环境变量配置
cd xxxxx/xxxx/xxxxxx/xxxxx   # cd到项目根目录
lettuce  # 执行用例

在这里插入图片描述

问题

无法实现在py脚本中import其他自定义包,不利于封装维护。还未解决此问题,不知道是因为版本替换的原因,还是lettuce本身的特征(怀疑是由于world的机制造成了这种现象,不过可以好好利用world机制)

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值