行为驱动python

行为驱动:自然语言映射到程序代码 应用场景:敏捷场景里用 (注释:行为驱动在敏捷开发里的应用)
注意事项:
1.目前lettuce只支持python2;lettuce 在这个路径 C:\Python27\Scripts
步骤:前置条件 py -2 -m pip install lettuce
2.必须新建features目录,否则执行会失败,目录结构如下:
features
-steps.py(写测试脚本和自然语言的测试步骤进行对应)
-xxxx.feature (写自然语言的测试步骤的)

运行:
法一:在features上级的目录下打开cmd 执行CMD命令,进来后,输入lettuce;features这个目录文件夹 是自己创建的
法二:在cmd中,cd进入features的父目录,执行lettuce

E:\PythonDemo\Glory\20190224\features
steps.py
zero.feature
就这俩文件

steps.py

#encoding=utf-8
from lettuce import *

#用于计算整数的阶乘函数
def factorial(number):
    number = int(number)
    if (number == 0) or (number == 1):
        return 1
    else:
        return reduce(lambda x, y: x * y, range(1, number + 1))

@step('I have the number (\d+)')
def have_the_number(step, number):
    # 将通过正则表达式匹配的数字存于全局变量world中
    world.number = int(number)

@step('I compute its factorial')
def compute_its_factorial(step):
    # 从全局变量world中取出匹配的数字,
    # 计算其阶乘,并将结果再存回world中
    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

zero.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

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

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

Scenario: Factorial of 3
Given I have the number 3
When I compute its factorial
Then I see the number 6

方法二“
私有,排重的方法,都不会跟测试步骤对应

第一个用函数
E:\PythonDemo\Glory\20190224\features
上面那2个文件

第2个用类的方法
E:\PythonDemo\Glory\201902241\features
steps.py zero.feature

steps.py

#encoding=utf-8
from lettuce import world, steps

def factorial(number):
  number = int(number)
  if (number == 0) or (number == 1):
    return 1
  else:
      return reduce(lambda x, y: x * y, range(1, number + 1))

@steps
class FactorialSteps(object):
    """Methods in exclude or starting with _ will not be considered as step"""

    exclude = ['set_number', 'get_number']

    def __init__(self, environs):
        # 初始全局变量
        self.environs = environs

    def set_number(self, value):
        # 设置全局变量中的number变量的值
        self.environs.number = int(value)

    def get_number(self):
        # 从全局变量中取出number的值
        return self.environs.number

    def _assert_number_is(self, expected, msg="Got %d"):
        number = self.get_number()
        # 断言
        assert number == expected, msg % number

    def have_the_number(self, step, number):
        '''I have the number (\d+)'''
        # 上面的三引号引起的代码必须写,并且必须是三引号引起
        # 表示从场景步骤中获取需要的数据
        # 并将获得数据存到环境变量number中
        self.set_number(number)

    def i_compute_its_factorial(self, step):
        """When I compute its factorial"""
        number = self.get_number()
        # 调用factorial方法进行阶乘结算,
        # 并将结算结果存于全局变量中的number中
        self.set_number(factorial(number))

    def check_number(self, step, expected):
        '''I see the number (\d+)'''
        # 上面的三引号引起的代码必须写,并且必须是三引号引起
        # 表示从场景步骤中获取需要的数据以便断言测试结果
        self._assert_number_is(int(expected))

FactorialSteps(world)

zero.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

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

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

Scenario: Factorial of 3
Given I have the number 3
When I compute its factorial
Then I see the number 6

BDD(Behavier Driven Data)使用多条用例,模拟数据库,类似于一个查询的操作
文件存储地方:
E:\PythonDemo\Glory\201902242\features
step.py

#encoding=utf-8
from lettuce import *

@step('I have the following students in my database:')
def students_in_database(step):
    if step.hashes:
        # 如果存在步骤表格数据,则继续后续步骤
        print type(step.hashes)
        assert step.hashes == [
            {
                'name': 'Anton',
                'monthly_due': '$ 500',
                'billed': 'no'
            },
            {
                'name': 'Jack',
                'monthly_due': '$ 400',
                'billed': 'no'
            },
            {
                'name': 'Gabriel',
                'monthly_due': '$ 300',
                'billed': 'no'
            },
            {
                'name': 'Gloria',
                'monthly_due': '$ 442.65',
                'billed': 'no'
            },
            {
                'name': 'Ken',
                'monthly_due': '$ 907.86',
                'billed': 'no'
            },
            {
                'name': 'Leonard',
                'monthly_due': '$ 742.84',
                'billed': 'no'
            },
        ]

@step('I bill names starting with "(.*)"')
def match_starting(step, startAlpha):
    # 将通过正则表达式匹配步骤中最后一个字母,
    # 并存于全局变量startAlpha中
    world.startAlpha = startAlpha
    print "no data exist:",step.hashes

@step('I see those billed students:')
def get_starting_with_G_student(step):
    # 遍历步骤数据表中的数据
    for i in step.hashes:
        # 断言学生的名字是否以world.startAlpha变量存取的的字母开头
        assert i["name"].startswith(world.startAlpha)

@step("those that weren't:")
def result(step):
    for j in step.hashes:
        # 断言学生名字不以world.startAlpha变量存取的的字母开头
        # 断言学生名字不以world.startAlpha变量存取的的字母开头
        assert world.startAlpha not in j["name"][0]

student.feature
Feature: bill students alphabetically
In order to bill students properly
As a financial specialist
I want to bill those which name starts with some letter

Scenario: Bill students which name starts with "G"
Given I have the following students in my database:
    | name     | monthly_due | billed |
    | Anton    | $ 500       | no     |
    | Jack     | $ 400       | no     |
    | Gabriel  | $ 300       | no     |
    | Gloria   | $ 442.65    | no     |
    | Ken      | $ 907.86    | no     |
    | Leonard  | $ 742.84    | no     |
When I bill names starting with "G"
Then I see those billed students:
    | name     | monthly_due | billed |
    | Gabriel  | $ 300       | no     |
    | Gloria   | $ 442.65    | no     |
And those that weren't:
    | name     | monthly_due | billed |
    | Anton    | $ 500       | no     |
    | Jack     | $ 400       | no     |
    | Ken      | $ 907.86    | no     |
    | Leonard  | $ 742.84    | no     |

sougou.feature
行为驱动 + webdriver + 数据驱动的例子
terrain 装饰器 自动执行 做准备 做清理
前提条件 :
py -2 -m pip install selenium
sogou.feature
sogou.py
terrain.py

sogou.feature
Feature: Search in Sogou website
In order to Search in Sogou website
As a visitor
We’ll search the NBA best player

Scenario: Search NBA player
Given I have the english name “<search_name>”
When I search it in Sogou website
Then I see the entire name “<search_result>”

Examples:
| search_name | search_result |
| Jordan | Michael |
| Curry | Stephen |
| Kobe | Bryant |

sogou.py

#encoding=utf-8
from lettuce import *
from selenium import webdriver
import time

@step('I have the english name "(.*)"')
def have_the_searchWord(step, searchWord):
    world.searchWord = str(searchWord)
    print world.searchWord

@step('I search it in Sogou website')
def search_in_sogou_website(step):
    world.driver = webdriver.Ie(executable_path = "d:\\chromedriver.exe")
    world.driver.get("http://www.sogou.com")
    world.driver.find_element_by_id("query").send_keys(world.searchWord)
    world.driver.find_element_by_id("stb").click()
    time.sleep(3)

@step('I see the entire name "(.*)"')
def check_result_in_sogou(step, searchResult):
    assert searchResult in world.driver.page_source, "got word:%s" %searchResult
    world.driver.quit()

terrain.py

#encoding=utf-8
from lettuce import *
import logging

#初始化日志对象
logging.basicConfig(
    # 日志级别
    level = logging.INFO,
    # 日志格式
    # 时间、代码所在文件名、代码行号、日志级别名字、日志信息
    format = '%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
    # 打印日志的时间
    datefmt = '%a, %Y-%m-%d %H:%M:%S',
    # 日志文件存放的目录(目录必须存在)及日志文件名
    filename = 'e:/BddDataDriveRreport.log',
    # 打开日志文件的方式
    filemode = 'w'
)
#在所有场景执行前执行
@before.all
def say_hello():
    logging.info("Lettuce will start to run tests right now...")
    print "Lettuce will start to run tests right now..."

#在每个secnario开始执行前执行
@before.each_scenario
def setup_some_scenario(scenario):
    # 每个Scenario开始前,打印场景的名字
    print 'Begin to execute scenario name:' + scenario.name
    # 将开始执行的场景信息打印到日志
    logging.info('Begin to execute scenario name:' + scenario.name)

#每个step开始前执行
@before.each_step
def setup_some_step(step):
    run = "running step %r, defined at %s" % (
        step.sentence, # 执行的步骤
        step.defined_at.file # 步骤定义在哪个文件
    )
    # 将每个场景的每一步信息打印到日志
    logging.info(run)

#每个step执行后执行
@after.each_step
def teardown_some_step(step):
    if not step.hashes:
       print "no tables in the step"   #会被打印9次,因为我们仅仅设定了场景的table,而不是给每个步骤设定table
                                       #注意每个step可以有自己的table,等价于把table的数据作为一个字典传入到程序中使用。
       logging.info("no tables in the step")

#在每个secnario执行结束执行
@after.each_scenario
def teardown_some_scenario(scenario):
    print  'finished, scenario name:' + scenario.name
    logging.info('finished, scenario name:' + scenario.name)

#在所有场景开始执行后执行
@after.all #默认获取执行结果的对象作为total参数
def say_goodbye(total):
    result = "Congratulations, %d of %d scenarios passed!" % (
        total.scenarios_ran,  #一共多少场景运行了
        total.scenarios_passed #一共多少场景运行成功了
    )
    print result
    logging.info(result)
    # 将测试结果写入日志文件
    logging.info("Goodbye!")
    print "------ Goodbye! ------"

基于中文的行为驱动:中文feature
baidu.feature
terrain.py
log.py
baidu.feature
在默认编码为GBK的Windows系统中执行场景使用中文描述的行为驱动测试时,打印到控制台的场景等信息,中文会出现乱码,这是由于lettuce框架将输出到控制台的场景描述信息转成UTF8编码的字符导致的。下面针对lettuce(0.2.23)版本给出具体解决方法。
(1)进入Python安装目录中lettuce安装路径中的plugins目录中,
比如本地路径为C:\Python27\Lib\site-packages\lettuce\plugins。
(2)找到该目录下的colored_shell_output.py文件,
(3)打开该文件,找到该文件的第32行代码what = what.encode(‘utf-8’)
,将其改成what = what#.encode(‘utf-8’)

程序见 E:\PythonDemo\Glory\201902244\features

baidu.feature
#encoding=utf-8
#language: zh-CN

特性: 在百度网址搜索IT相关书籍
能够搜索到书的作者,比如吴晓华

场景: 在百度网站搜索IT相关书籍
    如果将搜索词设定为书的名字"<书名>"
    当打开百度网站
    和在搜索输入框中输入搜索的关键词,并点击搜索按钮后
    那么在搜索结果中可以看到书的作者"<作者>"

例如:
    | 书名                         | 作者   |
    | Selenium WebDriver实战宝典   | 吴晓华 |
    | HTTP权威指南                 | 协议 |
    | Python核心编程               | Python |

terrain.py

#encoding=utf-8
from lettuce import *
from log import *

#在所有场景执行前执行
@before.all
def say_hello():
    logging.info(u"开始执行行为数据驱动测试...")

#在每个secnario开始执行前执行
@before.each_scenario
def setup_some_scenario(scenario):
    # 将开始执行的场景信息打印到日志
    logging.info(u'开始执行场景“%s”' %scenario.name)

#每个step开始前执行
@before.each_step
def setup_some_step(step):
    world.stepName = step.sentence
    run = u"执行步骤“%s”, 定义在“%s”文件" % (
        step.sentence, # 执行的步骤
        step.defined_at.file # 步骤定义在哪个文件
    )
    # 将每个场景的每一步信息打印到日志
    logging.info(run)

#每个step执行后执行
@after.each_step
def teardown_some_step(step):
    logging.info(u"步骤“%s”执行结束" % world.stepName)

#在每个secnario执行结束执行
@after.each_scenario
def teardown_some_scenario(scenario):
    logging.info(u'场景“%s”执行结束' %scenario.name)
	
#在所有场景开始执行后执行
@after.all #默认获取执行结果的对象作为total参数
def say_goodbye(total):
    result = u"恭喜,%d个场景运行,%d个场景运行成功" % (
        total.scenarios_ran,  #一共多少场景运行了
        total.scenarios_passed #一共多少场景运行成功了
    )
    logging.info(result)
    # 将测试结果写入日志文件
    logging.info(u"本次行为数据驱动执行结束")

log.py

#encoding=utf-8
import logging

#初始化日志对象
logging.basicConfig(
    # 日志级别
    level = logging.INFO,
    # 日志格式
    # 时间、代码所在文件名、代码行号、日志级别名字、日志信息
    format = '%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
    # 打印日志的时间
    datefmt = '%a, %Y-%m-%d %H:%M:%S',
    # 日志文件存放的目录(目录必须存在)及日志文件名
    filename = 'e:/BddDataDriveRreport.log',
    # 打开日志文件的方式
    filemode = 'w'
)

批量执行多个feature
E:\PythonDemo\Glory\201902245\features
中英文 文件
d:\chromedriver.exe
演示示例所需文件如下:
Login_Chinese.feature
Login_Chinese.py
Login_English.feature
Login_English.py
terrain.py

Login_Chinese.feature
#encoding=utf-8
#language: zh-CN

特性: 登录126邮箱和退出126邮箱登录

场景: 成功登录126邮箱
    假如启动一个浏览器
    当用户访问http://mail.126.com网址
    当用户输入输入用户名“axu28990@126.com”和对应的邮箱密码
    那么页面会出现“未读邮件”关键字

场景: 成功退出126邮箱
    当用户从页面单击退出链接
    那么页面显示“您已成功退出网易邮箱”关键内容

Login_Chinese.py

#encoding=utf-8
#language: zh-CN
from lettuce import *
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time

@step(u'启动一个浏览器')
def open_browser(step):
    try:
        # 创建Chrome浏览器的driver实例,并存于全局对象world中,
        # 供后续场景或步骤函数使用
        world.driver = webdriver.Chrome(executable_path = "d:\\chromedriver.exe")
    except Exception, e:
        raise e

@step(u'用户访问(.*)网址')
def visit_url(step, url):
    print url
    world.driver.get(url)

@step(u'用户输入输入用户名“(.*)”和密码“(.*)”')
def user_enters_UserName_and_Password(step, username, password):
    print username, password
    # 浏览器窗口最大化
    world.driver.maximize_window()
    time.sleep(3)
    # 切换进frame控件
    world.driver.switch_to.frame(world.driver.find_element_by_xpath("//iframe[contains(@id,'x-URS-iframe')]"))
    # 获取用户名输入框
    userName = world.driver.find_element_by_xpath('//input[@name="email"]')
    userName.clear()
    # 输入用户名
    userName.send_keys(username)
    # 获取密码输入框
    pwd = world.driver.find_element_by_xpath("//input[@name='password']")
    # 输入密码
    pwd.send_keys(password)
    # 发送一个回车键
    pwd.send_keys(Keys.RETURN)
    # 等待15秒,以便登录后成功进入登录后的页面
    time.sleep(15)

@step(u'页面会出现“(.*)”关键字')
def message_displayed_Login_Successfully(step, keywords):
    # print world.driver.page_source.encode('utf-8')
    # 断言登录成功后,页面是否出现预期的关键字
    assert keywords in world.driver.page_source
    # 断言成功后,打印登录成功信息
    print "Login Success"

@step(u'用户从页面单击退出链接')
def LogOut_from_the_Application(step):
    print "====",world.driver
    # time.sleep(5)
    # 点击退出按钮,退出登录
    world.driver.find_element_by_link_text(u"退出").click()
    time.sleep(8)

@step(u'页面显示“(.*)”关键内容')
def displayed_LogOut_Successfully(step, keywords):
    # 断言退出登录后,页面是否出现退出成功关键内容
    assert keywords in world.driver.page_source
    print u"Logout Success"
    # 退出浏览器
    world.driver.quit()

Login_English.feature
#encoding=utf-8

Feature: login and logout

Scenario: Successful Login with Valid Credentials
Given Launch a browser
When User visit to http://mail.126.com Page
And User enters UserName"axu28990" and Password"邮箱对应密码"
Then Message displayed Login Successfully

Scenario: Successful LogOut
    When User LogOut from the Application
    Then Message displayed LogOut Successfully

Login_English.py

#encoding=utf-8
from lettuce import *
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time

@step('Launch a browser')
def open_browser(step):
    try:
        world.driver =  webdriver.Chrome(executable_path = "d:\\chromedriver.exe")
    except Exception, e:
        raise e

@step('User visit to (.*) Page')
def visit_url(step, url):
    world.driver.get(url)

@step('User enters UserName"(.*)" and Password"(.*)"')
def user_enters_UserName_and_Password(step, username, password):
    world.driver.maximize_window()
    time.sleep(3)
    world.driver.switch_to.frame(world.driver.find_element_by_xpath('//iframe[contains(@id,"x-URS-iframe")]'))
    userName = world.driver.find_element_by_xpath('//input[@name="email"]')
    userName.clear()
    userName.send_keys(username)
    pwd = world.driver.find_element_by_xpath("//input[@name='password']")
    pwd.send_keys(password)
    pwd.send_keys(Keys.RETURN)
    time.sleep(15)

@step('Message displayed Login Successfully')
def message_displayed_Login_Successfully(step):
    # print world.driver.page_source.encode('utf-8')
    assert u"未读邮件" in world.driver.page_source
    print "Login Success"

@step('User LogOut from the Application')
def LogOut_from_the_Application(step):
    print "====",world.driver
    # time.sleep(15)
    world.driver.find_element_by_partial_link_text(u"退出").click()
    time.sleep(4)

@step('Message displayed LogOut Successfully')
def displayed_LogOut_Successfully(step):
    assert u"您已成功退出网易邮箱" in world.driver.page_source
    print u"Logout Success"
    world.driver.quit()

terrain.py

#encoding=utf-8
from lettuce import *

#在所有场景执行前执行
@before.all
def say_hello():
    print u"开始执行行为数据驱动测试..."

#在每个secnario开始执行前执行
@before.each_scenario
def setup_some_scenario(scenario):
    print u'开始执行场景“%s”' %scenario.name

#在每个secnario执行结束后执行
@after.each_scenario
def teardown_some_scenario(scenario):
    print u'场景“%s”执行结束' %scenario.name

#在所有场景执行结束后执行
@after.all #默认获取执行结果的对象作为total参数
def say_goodbye(total):
    result = u"恭喜,%d个场景被运行,%d个场景运行成功" % (
        total.scenarios_ran,  #一共多少场景运行了
        total.scenarios_passed #一共多少场景运行成功了
    )
    print result
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值