3

I am currently using Behave (BDD for Python) and have been digging in the source code to understand how the @given, @when and @then decorators are being declared.

The farthest I've gone is to look at step_registry.py where I found the function setup_step_decorators(context=None, registry=registry) which appears to be doing the job.

However, I don't quite understand how these decorators are created since they don't appear to be explicitly declared in the source code in the form of a def when(...):. I am under the impression that they are declared based on a list of strings (for step_type in ('given', 'when', 'then', 'step'):) that is then processed by a call to make_decorator().

Can someone walk me through the code and explain where/how these decorators are being declared?

Here is where you can get access to the source code of Behave.

4

2 回答 2

5

好吧,让我们从外部开始:

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
于 2014-08-09T00:58:14.247 回答
3

它们被注入到globals()第 90 行左右(那时contextglobals()因为contextis 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
于 2014-08-09T00:58:05.457 回答