BDD - Python Behave 数据共享 context
BDD - Python Behave 数据共享 context
引言
在 step 实现过程中,会涉及到数据通讯,step 之间,feature 之间,甚至整个执行期间的数据共享。
Python 只在定义变量的函数中保持变量有效。我们不能在定义这些变量的函数之外访问它们。但是,Behave step 实现过程,可能需要将数据从第一个函数发送到第二个函数。注意定义全局变量也不是一个好的做法。原因是,全局变量只在定义它们的文件中有用。这些不能在文件外部使用。在测试期间,我们将有许多步骤定义,我们可能需要在所有地方共享相同的信息。全局变量在这里没有任何帮助。
Behave 提供一种机制实现数据共享,今天我们就来了解一下 Behave context。
想了解更多 Behave 相关的文章,欢迎阅读《Python BDD Behave 系列》,持续更新中。
Behave context
Context 是 Python Behave 中非常重要的特性,用户和 Behave 可以在其中存储共享信息。它保存测试执行期间的上下文信息。它是一个对象,可以将用户定义的数据与 Python Behave 定义的数据一起存储在上下文属性中。它运行在 Python Behave 自动管理的三个级别( feature 功能、scenario 场景和 test run 测试运行期间)上。
每当 Python Behave 启动到一个新的特性或场景时,都会向上下文添加一个新层。这允许新的活动级别添加新的值或覆盖之前为该活动期间定义的值。这可以称为作用域。
值可以在环境控制文件中定义值,例如 environment.py,它可以在 feature 级别设置,然后在某些 Scenario 场景中重写。在 Scenario 场景级别做出的更改不会永久影响在 feature 级别设置的值。在所有情况下,Context 变量都是 behave.runner.Context 的一个实例。
Context Attributes
一个 context 对象 (behave.runner.Context)传递于:
- step definitions (step implementations)
- behave hooks (before_all(), before_feature(), …, after_all())
Behave Attributes
behave runner 在测试运行期间为 context 对象分配多个属性。
 注意用户不能更改 context 对象的 Behave attributes. 
| Attribute Name | Layer | Type | Description | 
|---|---|---|---|
| config | test run | Configuration | Configuration that is used. | 
| aborted | test run | bool | Set to true if test run is aborted by the user. | 
| failed | test run | bool | Set to true if a step fails. | 
| feature | feature | Feature | Current feature. | 
| tags | feature, scenario | list | Effective tags of current feature, scenario, scenario outline. | 
| active_outline | scenario outline | Row | Current row in a scenario outline (in examples table). | 
| scenario | scenario | Scenario | Current scenario. | 
| log_capture | scenario | LoggingCapture | If logging capture is enabled. | 
| stdout_capture | scenario | StringIO | If stdout capture is enabled. | 
| stderr_capture | scenario | StringIO | If stderr capture is enabled. | 
| table | step | Table | Contains step’s table, otherwise None. | 
| text | step | String | Contains step’s multi-line text (unicode), otherwise None. | 
User Attributes
用户可以为 context 对象分配(或修改)自定义的属性。但是,这些属性将根据定义这些属性的位置再次从上下文对象中删除。
| Kind | Assign Location | Lifecycle Layer (Scope) | 
|---|---|---|
| Hook | before_all() | test run | 
| Hook | after_all() | test run | 
| Hook | before_tags() | feature or scenario | 
| Hook | after_tags() | feature or scenario | 
| Hook | before_feature() | feature | 
| Hook | after_feature() | feature | 
| Hook | before_scenario() | scenario | 
| Hook | after_scenario() | scenario | 
| Hook | before_step() | scenario | 
| Hook | after_step() | scenario | 
| Step | Step definition | scenario | 
Context Attributes 应用
下在通过简单的实例来了解一下 Context Attributes 应用
Context behave attributes 应用
context.text
通过 context.text 访问多行文本 “”" “”" 之间的内容
Given user enters name and password
		"""
		Demo Behave
		Topic – Multiline Text
		"""
@given('user enters name and password')
def step_impl(context):
     # access multiline text with .text attribute
     print(f"Print Multiline Text: {context.text}\n")
context.table
通过 context.table 访问 table 信息
Given the following employees are registered
			| Name         | Department | Salary |
			| Alice        | HR         | 50000  |
			| Bob          | IT         | 60000  |
			| Charlie      | Marketing  | 55000  |
@given('the following employees are registered')
def step_register_employees(context):
    # Store the employee data in context.employees
    context.employees = context.table
    # Go through each row of the table and get the value of each row
    for row in context.table:
        name = row['Name']
        department = row['Department']
        salary = row['Salary']
        print(f"Print Name:{name}, Department:{department}, Salary:{salary}")
context.feature, context.scenario, context.tags
通过 context.feature, context.scenario, context.tags 来访问 behave 属性
Then I print the context information
@then('I print the context information')
def step_print_context_information(context):
    # print context.feature、context.scenario and context.tag info
    print(f"Feature: {context.feature.name}")
    print(f"Scenario: {context.scenario.name}")
    print(f"Tag: {context.tags}")
完整的例子
feature 文件
Feature: Context Behave Attribution Example
	@context_text_example
	Scenario: Check login functionality
		Given user enters name and password
		"""
		Demo Behave
		Topic – Multiline Text
		"""
		Then user should be logged in
        and I print the context information 
	@context_table_example
	Scenario: Add employees
		Given the following employees are registered
			| Name         | Department | Salary |
			| Alice        | HR         | 50000  |
			| Bob          | IT         | 60000  |
			| Charlie      | Marketing  | 55000  |
		When I view the list of employees
		Then I should see the following employees
			| Name         | Department | Salary |
			| Alice        | HR         | 50000  |
			| Bob          | IT         | 60000  |
			| Charlie      | Marketing  | 55000  |
        and I print the context information    
step 文件
from behave import *
@given('user enters name and password')
def step_impl(context):
    #access multiline text with .text attribute
    print(f"Print Multiline Text: {context.text}\n")
@then('user should be logged in')
def step_impl(context):
      pass
@given('the following employees are registered')
def step_register_employees(context):
    # Store the employee data in context.employees
    context.employees = context.table
@when('I view the list of employees')
def step_view_employee_list(context):
    # Assume some action to view the list of employees
    pass
@then('I should see the following employees')
def step_verify_employee_list(context):
    # Assume some logic to retrieve the current list of employees
    current_employees = context.employees
    # Go through each row of the table and get the value of each row
    for row in context.table:
        name = row['Name']
        department = row['Department']
        salary = row['Salary']
        print(f"Print Name:{name}, Department:{department}, Salary:{salary}")
    # Compare the expected and current employees
    assert current_employees == context.table
@then('I print the context information')
def step_print_context_information(context):
    # print context.feature、context.scenario and context.tag 
    print(f"Feature: {context.feature.name}")
    print(f"Scenario: {context.scenario.name}")
    print(f"Tag: {context.tags}")
执行结果
PS C:\Automation\Test> behave
Feature: Context Behave Attribution Example # BDD/Features/context_example/context_example.feature:1
  @context_text_example
  Scenario: Check login functionality   # BDD/Features/context_example/context_example.feature:4
    Given user enters name and password # BDD/steps/context_example.py:3
      """
      Demo Behave
      Topic – Multiline Text
      """
Print Multiline Text: Demo Behave
Topic – Multiline Text
    Then user should be logged in       # BDD/steps/context_example.py:8
    And I print the context information # BDD/steps/context_example.py:37
Print Feature: Context Behave Attribution Example
Print Scenario: Check login functionality
Print Tag: {'context_text_example'}
  @context_table_example
  Scenario: Add employees                        # BDD/Features/context_example/context_example.feature:14
    Given the following employees are registered # BDD/steps/context_example.py:12
      | Name    | Department | Salary |
      | Alice   | HR         | 50000  |
      | Bob     | IT         | 60000  |
      | Charlie | Marketing  | 55000  |
    When I view the list of employees            # BDD/steps/context_example.py:17
    Then I should see the following employees    # BDD/steps/context_example.py:22
      | Name    | Department | Salary |
      | Alice   | HR         | 50000  |
      | Bob     | IT         | 60000  |
      | Charlie | Marketing  | 55000  |
Print Name:Alice, Department:HR, Salary:50000
Print Name:Bob, Department:IT, Salary:60000
Print Name:Charlie, Department:Marketing, Salary:55000
    And I print the context information          # BDD/steps/context_example.py:37
Print Feature: Context Behave Attribution Example
Print Scenario: Add employees
Print Tag: {'context_table_example'}
1 feature passed, 0 failed, 0 skipped
2 scenarios passed, 0 failed, 0 skipped
7 steps passed, 0 failed, 0 skipped, 0 undefined
Took 0m0.020s
Context user attributes 应用
举个简单粗暴的例子吧,能说明问题就可以了,用户可以在 step 实现或 hooks 中自定义变量,注意这些变量的作用域。
feature 文件
Feature: Context User Attribution Example
@user_attr_1
	Scenario: User Attribution Scenario 1
		Given Set name as "Tom"
		then the name is "Tom"
@user_attr_2
	Scenario: User Attribution Scenario 2
		Given Set name as "Xiao Zhang"
		then the name is "Xiao Zhang"
hooks environment.py 文件
在不同级别的 hooks 设置的变量,作用域也是不一样的。
 e.g.
 before_all 中定义的变量是整个运行期间都是共享的
 before_feature 中定义的变量是feature 范围内共享
 before_scenario 中定义的变量是 scenario 范围内共享
 before_tag 中定义的变量是 feature 或 scenario 范围内共享
# environment.py
from behave import *
def before_all(context):
    pass
    # print("Before all tests")
    context.before_all = "before all"
def before_feature(context, feature):
    pass
    # print(f"Before feature: {feature.name}")
    context.before_feature = f"before {feature.name} feature"
def before_scenario(context, scenario):
    pass
    # print(f"Before scenario: {scenario.name}")
    context.before_scenario = f"before {scenario.name} scenario"
def before_tag(context, tag):
    pass
    # print(f"Before tag: {tag}")
    context.before_tag = f"before {tag} tag"
step 文件
step 实现中设置了变量 context.user_name,它的作用域只在本 scenario 范围,可以在本 scenario 里 step 之间共享。
 同时 step 也可以访问 hooks 自定义的变量
from behave import *
@given('Set name as {name}')
def get_user_attri(context, name):
    #access multiline text with .text attribute
    print(f"context.before_all: {context.before_all}")
    print(f"context.before_feature: {context.before_feature}")
    print(f"context.before_scenario: {context.before_scenario}")
    print(f"context.before_tag: {context.before_tag}")
    context.user_name = name
@then("the name is {name}")
def get_name(context, name):
    assert context.user_name == name    
执行结果
注意 print 输出信息,需要 behave 配置文件 behave.ini 中设置 stdout_capture = false 或则执行命令 behave – no-capture
PS C:\Automation\Test> behave
Feature: Context User Attribution Example # BDD/Features/context_example/context_user_attribution_example.feature:1
  @user_attr_1
  Scenario: User Attribution Scenario 1  # BDD/Features/context_example/context_user_attribution_example.feature:4
    Given Set name as "Tom"              # BDD/steps/context_user_attribution_example.py:4
context.before_all: before all
context.before_feature: before Context User Attribution Example feature
context.before_scenario: before User Attribution Scenario 1 scenario
context.before_tag: before user_attr_1 tag
    Then the name is "Tom"               # BDD/steps/context_user_attribution_example.py:14
  @user_attr_2
  Scenario: User Attribution Scenario 2  # BDD/Features/context_example/context_user_attribution_example.feature:9
    Given Set name as "Xiao Zhang"       # BDD/steps/context_user_attribution_example.py:4
context.before_all: before all
context.before_feature: before Context User Attribution Example feature
context.before_scenario: before User Attribution Scenario 2 scenario
context.before_tag: before user_attr_2 tag
    Then the name is "Xiao Zhang"        # BDD/steps/context_user_attribution_example.py:14
1 feature passed, 0 failed, 0 skipped
2 scenarios passed, 0 failed, 0 skipped
4 steps passed, 0 failed, 0 skipped, 0 undefined
Took 0m0.003s
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!