Lettuce(基于Python的BDD工具)

三世轮回 提交于 2020-01-13 03:44:30

一、Lettuce介绍

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是客户需求拉动的

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本身的特征

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!