0

假设我有一个定义如下的步骤:

 Then I would expect to see the following distribution for Ford
      | engine | doors | color |
      | 2.1L   | 4     | red   |

我有读取表并执行断言的步骤实现,如下所示:

@then('I would expect to see the following distribution for {car_type}')
def step(context, car_type):
    car = find_car_method(car_type)
    for row in context.table:
        for heading in row.headings:
            assertEqual(getattr(car, heading), 
                        row[heading], 
                        "%s does not match. " % heading + \
                        "Found %s" % getattr(car, heading))

(我这样做是因为这种方法允许添加更多字段,但保持其通用性足以用于检查汽车属性的许多用途)。

当我的汽车对象有 4 个门(作为 int)时,它不匹配,因为数据表要求有“4”个门(作为 unicode str)。

我可以实现这种方法来检查列的名称并对不同的字段进行不同的处理,但是当添加一个新字段时,维护变得更加困难,因为还有一个地方可以添加它。我宁愿在步骤数据表中指定它。就像是:

 Then I would expect to see the following distribution for Ford
      | engine | doors:int | color |
      | 2.1L   | 4         | red   |

有没有类似的东西可以用来实现这一点(因为这不起作用)?

请注意,在某些情况下,我需要从遇到相同问题的数据表中创建。尝试使用“汽车”对象的类型来确定类型是没有用的,因为在这种情况下它是 None 。

谢谢,

拜尔

4

1 回答 1

1

经过一番挖掘,我找不到任何东西,所以决定实施我自己的解决方案。我在这里发布它,因为它可能会在未来帮助某人。

我创建了一个辅助方法:

def convert_to_type(full_field_name, value):
    """ Converts the value from a behave table into its correct type based on the name
        of the column (header).  If it is wrapped in a convert method, then use it to
        determine the value type the column should contain.

        Returns: a tuple with the newly converted value and the name of the field (without the
                 convertion method specified).  E.g. int(size) will return size as the new field
                 name and the value will be converted to an int and returned.
    """
    field_name = full_field_name.strip()
    matchers = [(re.compile('int\((.*)\)'), lambda val: int(val)),
                (re.compile('float\((.*)\)'), lambda val: float(val)),
                (re.compile('date\((.*)\)'), lambda val: datetime.datetime.strptime(val, '%Y-%m-%d'))]
    for (matcher, func) in matchers:
        matched = matcher.match(field_name)
        if matched:
            return (func(value), matched.group(1))
    return (value, full_field_name)

然后我可以按场景设置如下:

Then I would expect to see the following distribution for Ford
  | engine | int(doors) | color |
  | 2.1L   | 4          | red   |

然后我逐步更改如下:

@then('I would expect to see the following distribution for {car_type}')
def step(context, car_type):
    car = find_car_method(car_type)
    for row in context.table:
        for heading in row.headings:
            (value, field_name) = convert_to_type(heading, row[heading])
            assertEqual(getattr(car, field_name), 
                        value, 
                        "%s does not match. " % field_name + \
                        "Found %s" % getattr(car, field_name))

每个人都应该将“匹配器”移动到模块级别,因为每次调用方法时都不必重新创建它们。它也很容易扩展它以获得更多的转换方法(例如 liter() 和 cc() 用于解析引擎大小,同时也转换为标准单位)。

于 2016-07-16T21:19:51.243 回答