如何在Python中为classmethod编写存根

leg*_*esh 0 python unit-testing

我有一个方法,它要求另一个类的类方法

def get_interface_params_by_mac(self, host, mac_unified):
        lines = RemoteCommand.remote_command(host, cls.IFCONFIG)
Run Code Online (Sandbox Code Playgroud)

...

class RemoteCommand(object):

    @classmethod
    def remote_command(cls, host, cmd, sh = None):
    ...
Run Code Online (Sandbox Code Playgroud)

我要为get_interface_params_by_mac方法编写一个单元测试,我想在其中更改remote_command的实现(我认为它调用存根 - 如果我错了就修复我)

在Python中用什么方法做到这一点?

Ale*_*lli 7

您的单元测试代码(可能在其setUp方法中,如果需要跨多个测试方法,因此有资格作为夹具)应该:

def fake_command(cls, host, cmd, sh=None):
  pass  # whatever you want in here
self.save_remote_command = somemodule.RemoteCommand.remote_command
somemodule.RemoteCommand.remote_command = classmethod(fake_command)
Run Code Online (Sandbox Code Playgroud)

然后撤消这个猴子修补(例如,tearDown如果修补完成,则在方法中setUp)

somemodule.RemoteCommand.remote_command = self.save_remote_command 
Run Code Online (Sandbox Code Playgroud)

在测试之后并不总是需要把东西放回去,但这是很好的一般做法.

更优雅的方法是通过依赖注入(DI)模式设计可测试性代码:

def __init__(self, ...):
   ...
   self.remote_command = RemoteCommand.remote_command
   ...

def set_remote_command_function(self, thefunction):
   self.remote_command = thefunction

def get_interface_params_by_mac(self, host, mac_unified):
        lines = self.remote_command(host, cls.IFCONFIG)
Run Code Online (Sandbox Code Playgroud)

DI以极低的成本为您带来了很大的灵活性(可测试性,但也在许多其他环境中),这使它成为我最喜欢的设计模式之一(我更愿意尽可能避免猴子修补).当然,如果您设计测试中的代码以使用DI,那么您在测试中需要做的就是通过set_remote_command_function使用您想要使用的任何伪函数调用实例来适当地准备该实例!