行爲驅動(2)

行爲驅動(2)
五、lettuce框架的步驟數據表格
實例:
(1)在PyCharm工具中建立以下所示的目錄結構及文件
..\lettuce\StepDataTables\features\student.features
..\lettuce\StepDataTables\features\steps.py
(2)student.feature文件具體內容以下 所示:ios

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     |

Given、Then及And步驟下都存在步驟數據表格,數據間以「|」進行分隔,數據表的第一行表示數據表的列名,不做爲數據存在。
(3)steps.py文件,用於編寫獲取student.feature文件中的數據,並提供後續操做,具體內容以下:web

#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 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變量存取的的字母開頭
        assert world.startAlpha not in j["name"][0]

六、 使用WebDriver進行英文語言的行爲數據驅動測試
測試邏輯:
(1)訪問http://www.sogou.com
(2)依次搜索幾個球星的英文名字中的一部分
(3)在搜索結果頁面斷言搜索的球星的全名正則表達式

實例:
(1)在PyCharm工具中建立以下所示的目錄結構及文件:
..lettuce\BddDataDrivenByEnglish\features\sogou.feature
..lettuce\BddDataDrivenByEnglish\features\sogou.py
..lettuce\BddDataDrivenByEnglish\features\terrain.py
(2)sogou.feature文件用於存放數據驅動所須要的數據,具體內容以下:shell

: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    |

Examples下面是一個場景數據表,數據間以「|」進行分隔,數據表的第一行表示數據表的列名,與場景中的變量名對應,好比Given I have the english name "<search_name>"語句中的search_name對應數據表中的search_name列
(3)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.Firefox(executable_path = "D:\\geckodriver")
    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()

(4)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 = "D:\\PythonProject\\BDD\\lettuce\\BddDataDrivenByEnglish\\BddDataDrivenReport.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..."

#在每一個Scenario開始執行前執行
@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,defind at % s" % (
        step.sentence, #執行的步驟
        step.defined_at.file #步驟定義在哪一個文件
    )
    #將每一個場景的每一步信息打印到日誌
    logging.info(run)

#每一個step執行後執行
@after.each_step
def teardown_some_step(step):
    logging.info("End of the:'%s'" % step.sentence)

#在每一個Scenario執行結束執行
@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!-------------"

七、使用WebDriver進行中文語言的行爲數據驅動測試
測試邏輯:
(1)訪問 http://www.baidu.com
(2)依次搜索幾本中文名字的書
(3)在搜索結果頁面斷言是否出現書的預期做者
實例:
(1)在PyCharm工具中建立以下所示的目錄結構及文件
..lettuce\BddDataDrivenByChinese\features\baidu.feature
..lettuce\BddDataDrivenByChinese\features\baidu.py
..lettuce\BddDataDrivenByChinese\features\terrain.py
..lettuce\BddDataDrivenByChinese\features\log.py
(2)baidu.feature文件內容以下:框架

#encoding=utf-8
# language: zh-CN

特性: 在百度網址搜索IT相關書籍
    可以搜索到書的做者,好比吳曉華

    場景: 在百度網站搜索IT相關書籍
        若是將搜索詞設定爲書的名字"<書名>"
        當打開百度網站
        和在搜索輸入框中輸入搜索的關鍵詞,並點擊搜索按鈕後
        那麼在搜索結果中能夠看到書的做者"<做者>"

    例如:
        | 書名                         | 做者   |
        | Selenium WebDriver實戰寶典   | 吳曉華 |
        | HTTP權威指南                 | 協議 |
        | Python核心編程               | Python |

(3)baidu.py文件內容以下:函數

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

@step(u'將搜索詞設定爲書的名字"(.*)"')
def have_the_searchWord(step,searchWord):
    world.searchWord = searchWord
    print world.searchWord

@step(u'打開百度網站')
def visit_baidu_website(step):
    world.driver = webdriver.Firefox(executable_path = "D:\\geckodriver")
    world.driver.get("http://www.baidu.com")

@step(u'在搜索輸入框中輸入搜索的關鍵詞,並點擊搜索按鈕後')
def search_in_sogou_website(step):
    world.driver.find_element_by_id("kw").send_keys(world.searchWord)
    world.driver.find_element_by_id("su").click()
    time.sleep(3)

@step(u'在搜索結果中能夠看到書的做者"(.*)"')
def check_result_in_sogou(step,searchResult):
    assert searchResult in world.driver.page_source , "not got words: %s" % searchResult
    world.driver.quit()

(4)terrain.py文件內容以下:工具

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

#在全部場景執行前執行
@before.all
def say_hello():
    logging.info(u"開始執行行爲數據驅動測試...")

#在每一個scenario開始前執行
@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)

#在每一個scenario執行結束後執行
@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'本次行爲數據驅動執行結束')

(5)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 = "D:\\PythonProject\\BDD\\lettuce\\BddDataDrivenByChinese\\BddDataDrivenReport.log",
    #打開日誌的方式
    filemode = "w"
)

Lettuce支持中文語言編寫的測試場景,是經過在場景文件以及測試場景的腳本文件的頂部添加# language:zh-CN,聲明使用的語言爲中文,同時,feature文件的編碼必須保存爲utf-8

八、批量執行行爲驅動用例集
lettuce支持一次執行多個用例,也就是放到features目錄下的多個.feature文件。
實例:
在PyCharm工具中建立以下所示的目錄結構及文件
..lettuce\MultipleFeatures\feature\Login_Chinese.feature
..lettuce\MultipleFeatures\feature\Login_Chinese.py
..lettuce\MultipleFeatures\feature\Login_English.feature
..lettuce\MultipleFeatures\feature\Login_English.py
..lettuce\MultipleFeatures\terrain.py

Login_Chinese.feature文件具體內容以下:

#encoding=utf-8
# language: zh-CN

特性: 登陸126郵箱和退出126郵箱登陸

    場景: 成功登陸126郵箱
        假如啓動一個瀏覽器
        當用戶訪問https://mail.126.com網址
        當用戶輸入用戶名「chenyl_2019」和密碼「sxzycyl0910」
        那麼頁面會出現「未讀郵件」關鍵字

    場景: 成功退出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.Firefox(executable_path = "D:\\geckodriver")
        #瀏覽器窗口最大化
        world.driver.maximize_window()
        time.sleep(3)
    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.find_element_by_id("lbNormal").click()
    time.sleep(1)
    # 找到並切換進iframe控件
    # 目前126和163登陸的iframe的id也是動態變化,因此不能用id定位iframe
    iframe = world.driver.find_element_by_xpath('//iframe[contains(@id,"x-URS-iframe")]')
    world.driver.switch_to.frame(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)
    # 退出iframe
    world.driver.switch_to.default_content()

@step(u'頁面會出現"(.*)"關鍵字')
def message_dispalyed_Login_Successfully(step,keywords):
    #斷言登陸成功後,頁面是否出現預期的關鍵字
    assert keywords in world.driver.page_source
    #斷言成功後,打印登陸成功信息
    print "Login Success"

@step(u'用戶從頁面單擊退出連接')
def LogOut_from_the_Application(step):
    print "==============",world.driver
    #單擊退出按鈕,退出登陸
    world.driver.find_element_by_link_text(u"退出").click()
    time.sleep(3)

@step(u'頁面顯示"(.*)"關鍵內容')
def dispalyed_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"chenyl_2019" and Password"sxzycyl0910"
      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:
        #建立Chrome瀏覽器的driver實例,並在於全局對象world中,供後續場景或步驟函數使用
        world.driver = webdriver.Firefox(executable_path = "D:\\geckodriver")
        #瀏覽器窗口最大化
        world.driver.maximize_window()
        time.sleep(3)
    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):
    print username,password
    # 點擊切換成帳號密碼登陸
    world.driver.find_element_by_id("lbNormal").click()
    time.sleep(1)
    # 找到並切換進iframe控件
    # 目前126和163登陸的iframe的id也是動態變化,因此不能用id定位iframe
    iframe = world.driver.find_element_by_xpath('//iframe[contains(@id,"x-URS-iframe")]')
    world.driver.switch_to.frame(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)
    # 退出iframe
    world.driver.switch_to.default_content()

@step('Message displayed Login Successfully')
def message_dispalyed_Login_Successfully(step,keywords):
    #斷言登陸成功後,頁面是否出現預期的關鍵字
    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
    #單擊退出按鈕,退出登陸
    world.driver.find_element_by_link_text(u"退出").click()
    time.sleep(3)

@step('Message displayed LogOut Successfully')
def dispalyed_logOut_Successfully(step,keywords):
    #斷言退出登陸後,頁面是否出現退出成功關鍵內容
    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"開始執行行爲數據驅動測試..."

#在每一個Scenario開始執行前執行
@before.each_scenario
def setuo_some_scenario(scenario):
    print u"開始執行場景:'%s'" % scenario.name

#在每一個Scenario執行結束後執行
@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

九、解決中文描述的場景輸出到控制檯亂碼在默認編碼爲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') 或者刪除(註釋)

相關文章
相關標籤/搜索