是否有可能跨多行破解一个长的函数名?

我们的开发团队使用PEP8棉绒,需要80个字符最大生产线长度

当我用python编写unit testing时,我喜欢用描述性的方法名来描述每个testing的function。 然而,这经常导致我超出了字符的限制。

这是一个function太长的例子…

class ClientConnectionTest(unittest.TestCase): def test_that_client_event_listener_receives_connection_refused_error_without_server(self): self.given_server_is_offline() self.given_client_connection() self.when_client_connection_starts() self.then_client_receives_connection_refused_error() 

我的选项:

  • 你可以写更短的方法名称!

    我知道,但我不想失去testing名称的描述性。

  • 您可以在每个testing上面写多行注释,而不是使用长名称!

    这是一个不错的想法,但是当我在IDE(PyCharm)中运行testing时,我将无法看到testing名称。

  • 也许你可以用一个反斜杠(一个逻辑行连续字符)继续行。

    不幸的是,在Dan的回答中,这不是Python中的一个选项。

  • 你可以停止testing你的testing。

    这在某些方面是有道理的,但鼓励一个格式良好的testing套件是很好的。

  • 您可以增加线路长度限制。

    我们的团队喜欢有限制,因为它有助于在窄屏幕上保持代码的可读性,所以这不是最好的select。

  • 你可以从你的方法开始删除test

    这不是一个选项。 Python的testing运行器需要所有的testing方法来开始test ,否则将无法进行test

    编辑:一些testing跑步者让你指定一个正则expression式时,searchtestingfunction,但我宁愿不这样做,因为它是在项目上工作的每个人额外的设置。 另外,它并不真正回答原来的问题。

  • 您可以将EventListener分离到自己的类中,并单独进行testing。

    事件监听器在它自己的类(并被testing)。 这只是一个由ClientConnection内发生的事件触发的接口。 这种build议似乎有很好的意图,但误导了,并不能回答原来的问题。

  • 你可以使用像Behave一样的BDD框架。 它旨在expressiontesting。

    这是真的,我希望将来可以使用更多。 虽然我仍然想知道如何跨行分割函数名称。

最终…

Python中有一种方法可以将多个函数声明分成多行吗?

例如…

 def test_that_client_event_listener_receives_ connection_refused_error_without_server(self): self.given_server_is_offline() self.given_client_connection() self.when_client_connection_starts() self.then_client_receives_connection_refused_error() 

或者我会自己咬子弹,缩短呢?

不,这是不可能的。

在大多数情况下,从可读性和可用性的angular度来看,这样一个长名称是不可取的,尽pipe您的testing名称用例看起来相当合理。

Python的词汇规则不允许将单个标记(在这种情况下是标识符)分割成多行。 逻辑行继续字符( \在一行的末尾)可以将多条物理行连接成一条逻辑行,但不能在多条行中连接一条令牌

可以编写一个装饰器,为该方法改变.__name__

 def test_name(name): def wrapper(f): f.__name__ = name return f return wrapper 

然后你可以写:

 class ClientConnectionTest(unittest.TestCase): @test_name("test_that_client_event_listener_" "receives_connection_refused_error_without_server") def test_client_offline_behavior(self): self.given_server_is_offline() self.given_client_connection() self.when_client_connection_starts() self.then_client_receives_connection_refused_error() 

依靠Python连接源邻接string文字的事实。

根据这个问题的答案: 如何禁用特定文件中的pep8错误? ,使用# nopep8# noqa尾注释来禁用PEP-8长行。 知道什么时候打破规则很重要。 当然,Python的禅会会告诉你:“特例不足以打破规则”。

我们可以使用装饰器而不是方法,因为unittestdir(class)获取方法名称。

装饰器decorate_method将通过类方法并基于func_mapping字典重命名方法的名称。

从@Sean Vieira看到装饰师回答之后,我想到了这个问题

 import unittest, inspect # dictionary map short to long function names func_mapping = {} func_mapping['test_client'] = ("test_that_client_event_listener_receives_" "connection_refused_error_without_server") # continue added more funtion name mapping to the dict def decorate_method(func_map, prefix='test_'): def decorate_class(cls): for (name, m) in inspect.getmembers(cls, inspect.ismethod): if name in func_map and name.startswith(prefix): setattr(cls, func_map.get(name), m) # set func name with new name from mapping dict delattr(cls, name) # delete the original short name class attribute return cls return decorate_class @decorate_method(func_mapping) class ClientConnectionTest(unittest.TestCase): def test_client(self): # dummy print for testing print('i am test_client') # self.given_server_is_offline() # self.given_client_connection() # self.when_client_connection_starts() # self.then_client_receives_connection_refused_error() 

下面的unittesttesting运行显示完整的描述性函数名称,认为它可能适用于你的情况,虽然它可能听起来不那么优雅,可读性

 >>> unittest.main(verbosity=2) test_that_client_event_listener_receives_connection_refused_error_without_server (__main__.ClientConnectionTest) ... i am client_test ok 

针对问题的具体情况分类。 你提出的testing案例看起来非常像一个描述testing用例需要的步骤的自然语言格式

看看是否使用behave行为驱动程序开发风格框架将在这里更有意义。 你的“function”可能看起来像(看看given ,什么whenthen反映你有什么):

 Feature: Connect error testing Scenario: Client event listener receives connection refused error without server Given server is offline when client connect starts then client receives connection refused error 

还有相关的pyspecs软件包 ,来自最近对相关主题的回答的样例用法:

  • 写描述性的unit testing

较短的函数名称解决scheme有很多优点。 考虑一下你的实际function名称和已经提供的内容。

 test_that_client_event_listener_receives_connection_refused_error_without_server(self): 

当你运行它时,你已经知道这是一个testing吗? 你真的需要使用下划线吗? 这个名字真的需要被理解吗? 骆驼的情况就像可读? 下面的第一个例子是如何重写上面的(字符计数= 79):接受一个约定来使用一个小的常量字集合缩写甚至更有效,例如Connection = Conn,Error = Err。 使用缩写时,必须注意上下文,只有在不可能出现混淆时才使用它们 – 下面的第二个例子。 如果您接受在方法名称中没有实际需要提及客户端作为testing主题,因为该信息在类名称中,那么第三个示例可能是适当的。 (54)个字符。

ClientEventListenerReceivesConnectionRefusedErrorWithoutServer(个体经营):

ClientEventListenerReceivesConnRefusedErrWithoutServer(个体经营):

EventListenerReceiveConnRefusedErrWithoutServer(个体经营):

我也同意B Rad C的build议“在self.assert中使用描述性名称作为msg kwarg arg”您应该只对在testing套件运行时看到失败testing的输出感兴趣。 validation你已经写好了所有必要的testing,不应该依赖于方法名的详细说明。

PS我可能也会删除'WithoutServer'多余的。 在服务器由于任何原因而不能联系的情况下,客户端事件处理程序是否应该收到事件? (虽然tbh我认为,如果他们的客户端不能连接到服务器它会收到某种'连接不可用',连接拒绝build议可以find服务器,但拒绝连接本身会更好。

这种名字的需要可能暗示其他的气味。

 class ClientConnectionTest(unittest.TestCase): def test_that_client_event_listener_receives_connection_refused_error_without_server(self): ... 

ClientConnectionTest听起来相当宽泛(而且根本就不像一个可testing的单元),并且很可能是一个内部有大量testing的大类,可以重新聚焦。 喜欢这个:

 class ClientEventListenerTest(unittest.TestCase): def receives_connection_refused_without_server(self): ... 

“testing”在名称中没有用处,因为它是隐含的。

用你给我的所有代码,我最后的build议是:重构你的testing代码,然后重新探究你的问题(如果它仍然存在的话)。