python 行为中针对不同步骤名称显示的不明确步骤异常

Ambiguous Step exception shown for different step names in python behave

我在 steps 目录下有两个不同的 python 文件: driverlogon.pytriplogon.py

driverlogon.py 定义步骤

@when(u'enter the {driver_id}')
def step_enter_the_driver_id(context,driver_id):
    SelectDriver.input_driver(driver_id)

triplogon.py 定义步骤

@when(u'enter the configured block number')
def step_enter_the_configured_block_number(context):
    ByBlock.enter_block(context.block)

当我运行这个程序时,我得到以下错误信息
在这种情况下,它们有不同的文本,甚至函数的内容也不同。
为什么会这样,谁能帮我理解这个?提前致谢

Exception AmbiguousStep: @when('enter the configured block number') has already been defined in
  existing step @when('enter the {driver_id}') at steps/driverlogon.py:26
Traceback (most recent call last):
  File "C:\Program Files (x86)\Python\Lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Program Files (x86)\Python\Lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Program Files (x86)\Python\Scripts\behave.exe\__main__.py", line 7, in <module>
  File "c:\program files (x86)\python\lib\site-packages\behave\__main__.py", line 183, in main
    return run_behave(config)
  File "c:\program files (x86)\python\lib\site-packages\behave\__main__.py", line 127, in run_behave
    failed = runner.run()
  File "c:\program files (x86)\python\lib\site-packages\behave\runner.py", line 804, in run
    return self.run_with_paths()
  File "c:\program files (x86)\python\lib\site-packages\behave\runner.py", line 809, in run_with_paths
    self.load_step_definitions()
  File "c:\program files (x86)\python\lib\site-packages\behave\runner.py", line 796, in load_step_definitions
    load_step_modules(step_paths)
  File "c:\program files (x86)\python\lib\site-packages\behave\runner_util.py", line 412, in load_step_modules
    exec_file(os.path.join(path, name), step_module_globals)
  File "c:\program files (x86)\python\lib\site-packages\behave\runner_util.py", line 386, in exec_file
    exec(code, globals_, locals_)
  File "steps\triplogon.py", line 23, in <module>
    @when(u'enter the configured block number')
  File "c:\program files (x86)\python\lib\site-packages\behave\step_registry.py", line 92, in wrapper
    self.add_step_definition(step_type, step_text, func)
  File "c:\program files (x86)\python\lib\site-packages\behave\step_registry.py", line 58, in add_step_definition
    raise AmbiguousStep(message % (new_step, existing_step))
behave.step_registry.AmbiguousStep: @when('enter the configured block number') has already been defined in
  existing step @when('enter the {driver_id}') at steps/driverlogon.py:26

步骤定义的工作方式如下:

  • 你新建一个py文件
  • 您向该文件添加了一个新的函数定义
    • 在这种情况下,您的两个文件具有相同的函数名称,def step_impl
  • 您使用想要与之关联的功能文件文本装饰您的新功能
    • enter the {driver_id}
    • enter the configured block number
  • 当您 运行 行为时,程序会收集其所有特征文件及其所有步骤定义,然后尝试将两者相关联
  • 对于上面的示例,Behave 找到文本 enter the {driver_id},并将其与函数 step_impl
  • 相关联
  • 然后 Behave 找到文本 enter the configured block number,并尝试将其与其函数定义相关联,但发现函数 step_impl 已被定义并与特征文本相关联。不知道该怎么做,Behave 抛出 AmbiguousStep 异常让你知道函数名称已被使用两次。

要解决此问题,您需要确保您的函数名称在所有步骤定义文件中都是唯一的。因此,在您的情况下,您有两个文件,每个文件都定义了一个名为 step_impl 的函数。您应该做的是用唯一名称重命名这些函数,以便 Behave 可以在 运行 时间正确关联这些名称。为确保名称是唯一的,我建议选择与装饰文本紧密匹配的名称。如果是我写这些定义,我会重写如下:

driverlogon.py

@when(u'enter the {driver_id}')
def step_enter_the_driver_id(context,driver_id):
     SelectDriver.input_driver(driver_id)

triplogon.py

@when(u'enter the configured block number') 
def step_enter_the_configured_block_number(context):
   ByBlock.block_data(context.block)

编辑#1:

感谢您包含堆栈跟踪。由此看来,您在两个不同的文件中两次定义了相同的步骤:

File "steps\triplogon.py", line 23, in <module>
    @when(u'enter the configured block number')
  File "c:\program files (x86)\python\lib\site-packages\behave\step_registry.py", line 92, in wrapper
    self.add_step_definition(step_type, step_text, func)
  File "c:\program files (x86)\python\lib\site-packages\behave\step_registry.py", line 58, in add_step_definition
    raise AmbiguousStep(message % (new_step, existing_step))
behave.step_registry.AmbiguousStep: @when('enter the configured block number') has already been defined in
  existing step @when('enter the {driver_id}') at steps/driverlogon.py:26

您会注意到最上面一行写着:

File "steps\triplogon.py", line 23, in <module>
    @when(u'enter the configured block number')

表示步骤enter the configured block number定义在triplogon.py

然后跟踪的最后一行说:

behave.step_registry.AmbiguousStep: @when('enter the configured block number') has already been defined in
  existing step @when('enter the {driver_id}') at steps/driverlogon.py:26

表示在driverlogon.py

中也定义了enter the configured block number

确保仅在两个文件之一中定义了该步骤。

如果您想保留这些名称,可以这样写:

driverlogon.py

@when(u'enter the "{driver_id}"')
def step_enter_the_driver_id(context,driver_id):
     SelectDriver.input_driver(driver_id)

triplogon.py

@when(u'enter the configured block number') 
def step_enter_the_configured_block_number(context):
   ByBlock.block_data(context.block)

在这种情况下不会引发异常,但 driver_id 将作为字符串传递,步骤如下所示:

When enter the "10"

但是,如果您希望它被解析为 int 而不是您可以使用预定义的数据类型 d 在这种情况下如下所示:

@when(u'enter the "{driver_id:d}"')
def step_enter_the_driver_id(context,driver_id):
     SelectDriver.input_driver(driver_id)

https://behave.readthedocs.io/en/latest/parse_builtin_types.html

尽管@automationleg 的答案在这种特殊情况下可能是正确的,但歧义问题来自另一个方向,并不能总是通过使用双引号来解决。歧义可能仍然存在。

查看此工单了解详情:https://github.com/behave/behave/issues/435

正确的解决方案是对参数使用类型模式,否则将使用所有格解析器并尽可能多地消耗 - 为所谓的重复留出空间。

谢谢@Janos。
我将在此处提取 behave issue 结果以总结解决方案。

  1. 将类型说明符添加到参数(例如 :S 或 :d)

     @when(u'enter the {driver_id:S}')
     def step_enter_the_driver_id(context,driver_id):
         SelectDriver.input_driver(driver_id)
    
     @when(u'enter the configured block number')
     def step_enter_the_configured_block_number(context):
         ByBlock.enter_block(context.block)
    
  2. 先放更复杂(更长?)的定义。所以如果你把它放在一个文件中,它将是:

     @when(u'enter the configured block number')
     def step_enter_the_configured_block_number(context):
         ByBlock.enter_block(context.block)
    
     @when(u'enter the {driver_id}')
     def step_enter_the_driver_id(context,driver_id):
         SelectDriver.input_driver(driver_id)
    

或者检查重命名文件是否有效,定义更复杂的文件是否按字母顺序排列在另一个文件之前。