2009-11-05 5 views
0

J'ai une méthode qui appelle à une classmethod d'une autre classeComment écrire un talon pour un classmethod en Python

def get_interface_params_by_mac(self, host, mac_unified): 
     lines = RemoteCommand.remote_command(host, cls.IFCONFIG) 

...

class RemoteCommand(object): 

    @classmethod 
    def remote_command(cls, host, cmd, sh = None): 
    ... 

Je vais écrire une unité test pour get_interface_params_by_mac méthode, dans lequel je voudrais changer une implémentation de remote_command (je pense qu'il appelle stub - me corriger si je tort)

Quelle est la bonne façon de faire cela en Python?

Répondre

7

Votre code unité-test (peut-être dans sa méthode setUp, si cela est nécessaire à travers plusieurs méthodes d'essai et se qualifie donc comme un appareil) devrait faire:

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) 

puis défaire ce singe ragréage (par exemple dans la méthode tearDown si le patch se fait en setUp) par

somemodule.RemoteCommand.remote_command = self.save_remote_command 

il est pas toujours nécessaire de remettre les choses après un test, mais il est une bonne pratique générale.

Une approche plus élégante serait de concevoir votre code pour testabilité via le modèle d'injection de dépendance (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) 

DI vous achète beaucoup de flexibilité (testabilité-sage, mais aussi dans de nombreux autres contextes) à très peu de frais, ce qui en fait l'un de mes modèles de design préférés (je préfèrerais éviter les patchs de singe partout où je le peux). Bien sûr, si vous concevez votre code sous test pour utiliser DI, tout ce que vous devez faire dans votre test est de préparer cette instance de manière appropriée en appelant le set_remote_command_function de l'instance avec la fausse fonction que vous voulez utiliser!

+0

Merci, Alex. C'est exactement ce dont j'ai besoin. J'aimerais aussi lire quelque chose à propos de DI. Pourriez-vous me donner un lien? – legesh

+0

Une autre question ... Ai-je vraiment besoin d'une méthode set_remote_command_function? Comme je comprends, je peux écrire quelque chose comme ceci: myobj.remote_command = RemoteCommand.remote_command – legesh

+0

@legesh, pour DI, voir par exemple le PDF d'une présentation du mien à http://www.aleax.it/yt_pydi.pdf. Non, vous n'avez pas forcément besoin d'une méthode setter, l'attribution directe d'attributs (éventuellement via une propriété si vous avez besoin de faire une comptabilité sur de telles affectations) peut également fonctionner. –

Questions connexes