一、Lettuce介绍
BDD
了解lettuce需要先了解BDD,BDD是TDD的一种衍生,通过特定的BDD框架,用自然语言或类自然语言,按照编写用户故事或者用户用例的方式,以功能使用者的视角,描述并编写测试用例。
BDD源于TDD并优于测试驱动开发。
之所以说BDD优于测试驱动开发,并非空穴来风,主要原因如下:
- 更加以人为本:TDD更多关注于测试接口实现逻辑正确性,而BDD重点关注用户使用功能时的行为和结果是否与符合预期。
- 更加以人为本:TDD基本上是使用编程语言来描述测试用例,而BDD则是用自然语言来描述测试用例。
- 更加以人为本:TDD不关注客户价值,而BDD从客户价值开始书写
- 更加以人为本:TDD的需求文档和测试用例是分别存储的,而BDD的需求文档就是测试用例
- 更加以人为本:TDD要求所有被覆盖的接口都要进行良好重构,而BDD只要求对暴露给客户使用的接口甚至UI具有可测试性
- 更加以人为本:TDD更多是团队纪律或者领导推动的,而BDD是客户需求拉动的
Lettuce
学习BDD(行为驱动开发),业界流行的BDD框架是Ruby语言编写的Cumumber,不过对于用Python习惯的朋友可以学习一下Cumumber在Python下的衍生品-Lettuce。
lettuce 除了官方文档外,几乎找不到其它资料,为了理解lettuce,我们不妨多去看看cucumber 的资料。对于项目的自动化测试,它可以执行纯文本的功能描述,它允许我们用自然语言去描述个一个系统的行为。
可以学习别人分享的博客
二、Lettuce安装
Python2
命令行安装(当前的lettuce0.2.x版本仍然只支持python2)
pip install Lettuce
Python3
如果使用的是python3,安装会麻烦一些,因为lettuce目前只支持python2,幸亏Github有大佬更新的版本
https://github.com/sgpy/lettuce/tree/py3
pip3 install lettuce # 安装lettuce
git clone https://github.com/e0ne/lettuce.git # clone大佬源码在任意位置
cd lettuce # 进入源码项目
git checkout -b py3 origin/py3 # 创建python3分支并clone
python3 setup.py install --record logName # 安装支持python3的版本替换原lettuce,并且将文件路径记录下载方便卸载删除
此方法只是替换了lettuce的访问路径,调用的时候路径发生变化,但是pip3安装的版本仍在
卸载
python2 直接卸载即可
pip uninstall lettuce
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使用
项目文件结构介绍
|-- features # lettuce 会根据目录路径查找相关文件
| -- xxxx.feature # BDD 的描述文件
| -- xxxx.py # 相关的python方法脚本
可以根据自己的需要在features下再创建文件夹用于分类等,lettuce会自动读取featuress文件下所有文件
使用介绍
样例
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
描述文件
lettuce规定了一系列的语法,你按照它的规则 告诉它,它就可以理解你的需求。feture文件中的关键字的作用和单元测试中的关键字的对应关系如下:
脚本文件
steps里面都是使用@step这个注解来表示你要做的行为对应的代码实现。
对于内容替换则按照正则表达式的方式,将函数所需的参数直接按照顺序提取出来
执行
直接在根目录下执行lettuce即可,即features上一层文件夹执行
lettuce
结果
进行接口测试
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
进行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()
问题
无法实现在py脚本中import其他自定义包,不利于封装维护。还未解决此问题,不知道是因为版本替换的原因,还是lettuce本身的特征
来源:CSDN
作者:小冯先生
链接:https://blog.csdn.net/baidu_36943075/article/details/103851458