什么是 BDD 测试以及框架示例

2023-03-22   出处: guru99  作/译者:Thomas Hamilton/Yilia

什么是 BDD(行为驱动开发)测试?

BDD(Behavior-driven development)测试:是敏捷软件开发的一种技术,是TDD即测试驱动开发的延伸。 在 BDD 中,测试用例是用一种即使是非程序员也能阅读的自然语言编写的。

BDD 测试如何工作?

  假设你被指派在网上银行应用程序中创建资金转账模块。
有多种方法可以测试它:
●如果源帐户中有足够的余额,则应进行资金转帐
●如果目的地 a/c 详细信息正确,则应进行资金转帐
●如果用户输入的交易密码/RSA代码/安全认证正确,则应进行资金转账
●即使是银行假期也应该进行资金转账
●资金转账应在账户持有人设定的未来日期进行
  测试场景变得更加精细和复杂,因为我们考虑了额外的功能,例如间隔 Y 天/月的转账金额 X,当总金额达到 Z 时停止计划转账,等等。开发人员的普遍倾向是先开发功能,后编写测试代码。 正如上述案例所示,此案例的测试用例开发很复杂,开发人员会将测试推迟到发布时,此时他将进行快速但无效的测试。为了克服这个问题(行为驱动开发),BDD 应运而生。 它使开发人员可以轻松完成整个测试过程在 BDD 中,无论你编写什么,都必须进入 Given-When-Then 步骤。 让我们在 BDD 中考虑上面的相同示例:

Given that a fund transfer module in net banking application has been developed
And I am accessing it with proper authentication
WhenI shall transfer with enough balance in my source account
Or I shall transfer on a Bank Holiday
Or I shall transfer on a future date
And destination a/c details are correct
And transaction password/rsa code / security authentication for the transaction is correct
And press or click send button
Then amount must be transferred
And the event will be logged in log file

  写、读、懂不是很容易吗? 它涵盖了资金转账模块的所有可能测试用例,并且可以轻松修改以容纳更多测试用例。 此外,它更像是为资金转账模块编写文档。

什么是 REST API 测试?

  随着 REST 成为如今构建 API 的一种非常流行的风格,自动化 REST API 测试用例和 UI 测试用例变得同样重要。 所以基本上,这些 REST API 测试涉及分别使用方法 POST、GET、PUT 和 DELETE 测试 CRUD(创建-读取-更新-删除)操作。

什么是Behave?

  Behave 是流行的 Python BDD 测试框架之一。让我们看看 Behave 是如何工作的:
特征文件由业务分析师/发起人/任何包含行为场景的人编写。 它有一种自然语言格式来描述一个特征或一个特征的一部分,并带有预期结果的代表性例子这些场景步骤映射到用 Python 编写的步骤实现。并且可选地,有一些环境控制(在步骤、场景、功能或整个射击比赛之前和之后运行的代码)。让我们开始使用 Behave 设置我们的自动化测试框架。

在 Windows 上设置 BDD 测试框架 Behave

安装:
●从 https://www.python.org/ 下载并安装 Python 3
●在命令提示符下执行以下命令来安装 behave
●pip 安装behave
●IDE:我用过 PyCharm Community Edition https://www.jetbrains.com/pycharm/download
项目设置:
●创建一个新项目
●创建以下目录结构:

功能文件:

构建功能文件 Sample_REST_API_Testing.feature,其功能为对“帖子”服务执行 CRUD 操作。在示例中,使用了http://jsonplaceholder.typicode.com/ 发布示例 REST 服务。

示例 POST 场景

Scenario: POST post example ->Here we are considering creating new post item using 'posts' service
Given: I set post posts API endpoint ->This is prerequisite for the test which is setting URL of posts service
When: I set HEADER param request content type as "application/json."
And set request body
And send POST HTTP request ->This is actual test step of sending a post request
Then: Then I receive valid HTPP response code 201 
And Response body "POST" is non-empty-> This is verification of response body

同样的,可以将剩下的Scenarios写成下面这样:

Sample_REST_API_Testing.feature

Feature: Test CRUD methods in Sample REST API testing framework

Background:
    Given I set sample REST API url

Scenario: POST post example
  Given I Set POST posts api endpoint
 When I Set HEADER param request content type as "application/json." 
    And Set request Body
 And Send a POST HTTP request 
 Then I receive valid HTTP response code 201
    And Response BODY "POST" is non-empty. 


Scenario: GET posts example
  Given I Set GET posts api endpoint "1"
  When I Set HEADER param request content type as "application/json." 
    And Send GET HTTP request
  Then I receive valid HTTP response code 200 for "GET." 
    And Response BODY "GET" is non-empty


Scenario: UPDATE posts example
  Given I Set PUT posts api endpoint for "1"
  When I Set Update request Body
    And Send PUT HTTP request
  Then I receive valid HTTP response code 200 for "PUT." 
    And Response BODY "PUT" is non-empty


Scenario: DELETE posts example
  Given I Set DELETE posts api endpoint for "1"
  When I Send DELETE HTTP request
  Then I receive valid HTTP response code 200 for "DELETE."

步骤实施

  现在,对于上述场景中使用的功能步骤,可以在“steps”目录下的Python文件中编写实现。Behave 框架通过与特征文件谓词匹配的装饰器来识别 Step 函数。 例如,特征文件场景中的给定谓词搜索具有装饰器“给定”的步骤函数。 在 When 和 Then 上也有类似的匹配。 但在“But”、“And”的情况下,Step 函数采用与前一步相同的装饰器。 例如,如果’And’来自Given,则匹配的步骤函数装饰器是@given
例如,POST 的 when step 可以如下实现:

@when (u'I Set HEADER param request content type as "{header_conent_type}"')
Mapping of When, here notice “application/json” is been passed from feature file for "{header_conent_type}” . This is called as parameterization


def step_impl (context, header_conent_type):
This is step implementation method signature

request_headers['Content-Type'] = header_conent_type
Step implementation code, here you will be setting content type for request header

同样,step python文件中其他步骤的实现会是这样的:

sample_step_implementation.py

from behave import given, when, then, step
import requests

api_endpoints = {}
request_headers = {}
response_codes ={}
response_texts={}
request_bodies = {}
api_url=None

@given(u'I set sample REST API url')
def step_impl(context):
    global api_url
    api_url = 'http://jsonplaceholder.typicode.com'

# START POST Scenario
@given(u'I Set POST posts api endpoint')
def step_impl(context):
    api_endpoints['POST_URL'] = api_url+'/posts'
    print('url :'+api_endpoints['POST_URL'])

@when(u'I Set HEADER param request content type as "{header_conent_type}"')
def step_impl(context, header_conent_type):
    request_headers['Content-Type'] = header_conent_type

#You may also include "And" or "But" as a step - these are renamed by behave to take the name of their preceding step, so:
@when(u'Set request Body')
def step_impl(context):
    request_bodies['POST']={"title": "foo","body": "bar","userId": "1"}

#You may also include "And" or "But" as a step - these are renamed by behave to take the name of their preceding step, so:
@when(u'Send POST HTTP request')
def step_impl(context):
    # sending get request and saving response as response object
    response = requests.post(url=api_endpoints['POST_URL'], json=request_bodies['POST'], headers=request_headers)
    #response = requests.post(url=api_endpoints['POST_URL'], headers=request_headers) #https://jsonplaceholder.typicode.com/posts
    # extracting response text
    response_texts['POST']=response.text
    print("post response :"+response.text)
    # extracting response status_code
    statuscode = response.status_code
    response_codes['POST'] = statuscode

@then(u'I receive valid HTTP response code 201')
def step_impl(context):
    print('Post rep code ;'+str(response_codes['POST']))
    assert response_codes['POST'] is 201
# END POST Scenario

# START GET Scenario
@given(u'I Set GET posts api endpoint "{id}"')
def step_impl(context,id):
    api_endpoints['GET_URL'] = api_url+'/posts/'+id
    print('url :'+api_endpoints['GET_URL'])

#You may also include "And" or "But" as a step - these are renamed by behave to take the name of their preceding step, so:
@when(u'Send GET HTTP request')
def step_impl(context):
    # sending get request and saving response as response object
    response = requests.get(url=api_endpoints['GET_URL'], headers=request_headers) #https://jsonplaceholder.typicode.com/posts
    # extracting response text
    response_texts['GET']=response.text
    # extracting response status_code
    statuscode = response.status_code
    response_codes['GET'] = statuscode

@then(u'I receive valid HTTP response code 200 for "{request_name}"')
def step_impl(context,request_name):
    print('Get rep code for '+request_name+':'+ str(response_codes[request_name]))
    assert response_codes[request_name] is 200

@then(u'Response BODY "{request_name}" is non-empty')
def step_impl(context,request_name):
    print('request_name: '+request_name)
    print(response_texts)
    assert response_texts[request_name] is not None
# END GET Scenario

#START PUT/UPDATE
@given(u'I Set PUT posts api endpoint for "{id}"')
def step_impl(context,id):
    api_endpoints['PUT_URL'] = api_url + '/posts/'+id
    print('url :' + api_endpoints['PUT_URL'])

@when(u'I Set Update request Body')
def step_impl(context):
    request_bodies['PUT']={"title": "foo","body": "bar","userId": "1","id": "1"}

@when(u'Send PUT HTTP request')
def step_impl(context):
    # sending get request and saving response as response object  # response = requests.post(url=api_endpoints['POST_URL'], headers=request_headers) #https://jsonplaceholder.typicode.com/posts
    response = requests.put(url=api_endpoints['PUT_URL'], json=request_bodies['PUT'], headers=request_headers)
    # extracting response text
    response_texts['PUT'] = response.text
    print("update response :" + response.text)
    # extracting response status_code
    statuscode = response.status_code
    response_codes['PUT'] = statuscode
#END PUT/UPDATE

#START DELETE
@given(u'I Set DELETE posts api endpoint for "{id}"')
def step_impl(context,id):
    api_endpoints['DELETE_URL'] = api_url + '/posts/'+id
    print('url :' + api_endpoints['DELETE_URL'])

@when(u'I Send DELETE HTTP request')
def step_impl(context):
    # sending get request and saving response as response object
    response = requests.delete(url=api_endpoints['DELETE_URL'])
    # response = requests.post(url=api_endpoints['POST_URL'], headers=request_headers) #https://jsonplaceholder.typicode.com/posts
    # extracting response text
    response_texts['DELETE'] = response.text
    print("DELETE response :" + response.text)
    # extracting response status_code
    statuscode = response.status_code
    response_codes['DELETE'] = statuscode
#END DELETE

运行测试

现在,完成了测试脚本开发部分,可以开始运行测试了,在命令提示符下执行以下命令以运行feature文件:
C: \Programs\Python\Python37>behave -f pretty C:\<your project path>\features\feature_files_folder\Sample_REST_API_Testing.feature
这将显示如下测试执行结果:

报表显示在控制台

  让我们再看一件很酷的事情。由于用户总是喜欢以更具可读性和可展示性的格式查看测试结果,因此在 Allure 的帮助下以 HTML 格式生成报告。

报告

首先,你需要安装 Allure Behave 格式化程序 [https://docs.qameta.io/allure-report/]:现在执行以下命令:

For reports
>behave -f json -o<path-to-your-report-folder> Sample_REST_API_Testing.feature
<allure-bin folder path>> allure serve <path-to-your-report-folder>

这可以像这样的可呈现和信息丰富的格式生成测试结果报告:

Test Report in HTML Format

显示单个场景结果的测试报告

总结:

●BDD 是行为驱动的开发。 它是敏捷软件开发的技术之一。
●REST 已经成为当今构建 API 的一种非常流行的风格,自动化 REST API 测试用例和 UI 测试用例变得同样重要。
●BDD 有一种自然语言格式来描述一个特性或一个特性的一部分,并带有预期结果的代表性示例
●Behave 框架通过与特征文件谓词匹配的装饰器来识别 Step 函数
●BDD 测试框架示例:1) Cucumber 2) SpecFlow 3) Quantum 4) JBehave 5) Codeception


声明:本文为本站编辑转载,文章版权归原作者所有。文章内容为作者个人观点,本站只提供转载参考(依行业惯例严格标明出处和作译者),目的在于传递更多专业信息,普惠测试相关从业者,开源分享,推动行业交流和进步。 如涉及作品内容、版权和其它问题,请原作者及时与本站联系(QQ:1017718740),我们将第一时间进行处理。本站拥有对此声明的最终解释权!欢迎大家通过新浪微博(@测试窝)或微信公众号(测试窝)关注我们,与我们的编辑和其他窝友交流。
540° /5400 人阅读/0 条评论 发表评论

登录 后发表评论