我目前正在使用Behave (Python的BDD),并一直在源代码中挖掘,以了解如何声明@given
, @when
和@then
装饰符。
我走得最远的是看看step_registry.py
,我发现功能setup_step_decorators(context=None, registry=registry)
似乎正在做这项工作。
然而,我不太明白这些装饰器是如何创建的,因为它们似乎没有在源代码中以def when(...):
的形式显式声明。我的印象是它们是基于字符串列表(for step_type in ('given', 'when', 'then', 'step'):
)声明的,然后通过调用make_decorator()
来处理。
谁能告诉我代码和解释在哪里/如何声明这些装饰符?
让我们从外部开始:
if context is None:
context = globals()
for step_type in ('given', 'when', 'then', 'step'):
step_decorator = registry.make_decorator(step_type)
context[step_type.title()] = context[step_type] = step_decorator
我想是最后一行让你困惑了。
每个模块的全局命名空间只是一个字典。函数globals()
返回该字典。如果修改了该字典,就创建了新的模块全局变量。例如:
>>> globals()['a'] = 2
>>> a
2
在本例中,默认为context = globals()
。因此,对于第一个step_type
,您实际上是这样做的:
>>> globals()['given'] = step_decorator
它们在第90行左右被注入globals()
(此时context
是globals()
,因为context
是None
):
# -- Create the decorators
def setup_step_decorators(context=None, registry=registry):
if context is None:
context = globals()
for step_type in ('given', 'when', 'then', 'step'):
step_decorator = registry.make_decorator(step_type)
context[step_type.title()] = context[step_type] = step_decorator
你也可以自己这样做(globals()
就像一个普通的字典一样工作):
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> globals()['a'] = 5
>>> a
5