2017-07-20 3 views
0

J'ai cherché des heures. Je ne trouve personne qui essaie même de faire ça. Hmmm.Comment remplacer (pas patcher) une seule méthode dans un test d'unité python

Je crois que je dois remplacer une seule méthode dans une instance de classe. Je fais pas signifie patch(return_value=). Je dois faire la méthode en question faire quelque chose impliquant self.

Je vais essayer de le décomposer. Généreusement paraphraser et dont l'une des nombreuses choses que j'essayé, ce qui ne fonctionne pas ...

class SetupClass(object): 
    def set_some_stuff(self): 
     data_list = functon_cannot_be_run_on_test_platform() 
     self.something = data_list[0] 
     self.something_else = data_list[1] 

class UUT(object): 
    self.config = SetupClass() 
    assert self.config.something == 'foo' 

class UnitTests(TestCase): 

    @patch('SetupClass') 
    def test_UUT(self, mock1): 

     def WedgeClass(SetupClass): 
      def set_some_stuff(self): 
       self.something = 'foo' 
       pass # I'm a Python newbie, in too deep 

     wedge_class = WedgeClass() 
     mock1.return_value = wedge_class # doesn't work. context errors 

     uut = UUT() # <-- would crash here, because assert above 

On suppose que je ne peux pas apporter des modifications à UUT ou SetupClass.

Les tests ne peuvent même pas décoller parce que l'assertion échouera en raison de SetupClass.functon_cannot_be_run_on_test_platform(). Notez que simplement moquant SetupClass.functon_cannot_be_run_on_test_platform ne résoudra pas le problème, pour des raisons. Je pense que le seul moyen de contourner ce gâchis est de surcharger SetupClass.set_some_stuff. Je ne peux pas simplement me moquer de toute la classe, car UUT repose aussi fortement sur ses autres fonctionnalités. J'ai besoin de tout pour fonctionner tel quel, sauf cette méthode et J'ai besoin de cette méthode pour pouvoir accéder, self dans le même contexte que prévu initialement.

J'ai essayé différentes choses impliquant le sous-classement et la valeur de mock.return etc. Je préfère ne pas me souvenir de la douleur qui a causé. : p

Mon royaume pour le code piloté par les tests en premier lieu! Ce code contient une convolution de co-dépendances. : -/

+0

'class' doit être démarré avec classe' UUT', pas 'def UUT' et ident est hors – Gang

+0

@Gang ... oh ouais. Juste des fautes de frappe. J'ai déjà édité le pseudo code une douzaine de fois. Pardon. La version actuelle est plus proche de ce que j'ai réellement essayé. – gruvin

+0

'def WedgeClass' devrait être en dehors de' classe UnitTests'? 2 lignes dans 'class UUT' dans une fonction' __init __() 'ou d'autres fonctions? – Gang

Répondre

1

Outre les multiples erreurs dans le code exemple, je rédigeai du haut de ma tête au café ...

Le problème a été (la plupart du temps) que j'utilisais return_value au lieu de side_effect à "remplace" la classe corrigée avec ma propre sous-classe. Mon besoin, redéfini peut-être plus clairement maintenant, est de surcharger une seule méthode, set_some_stuff, dans une classe de l'unité testée (UUT) mais sans se moquer de la classe.

La méthode émet plusieurs instructions 'self.foo = bar' que je veux modifier à des fins de test. Ainsi, se moquer de la valeur de retour de la méthode (inutilisée) ne suffit pas ... et patch.object semble perdre son contexte de classe, "'self' unknown" ou similaire.

Enfin, voici le code de travail, faire ce que je dois ...

import unittest 
import mock 

class SetupClass(object): 
    def set_some_stuff(self): 
     data_list = ['data not available', 'on test_platform'] # CRASH! 
     self.something = data_list[0] 
     self.something_else = data_list[1] 

class UUT: 
    def __init__(self): 
     self.config = SetupClass() 
     self.config.set_some_stuff() 
     assert self.config.something == 'foo' # <-- used to crash before here ... 
     self.got_here = True # ... but now the override method from 
          # WedgeClass is being used! :=) 

""" 
Subclass the original class, overriding just the method in question. Then set 
the subclass as the side_effect of the patched original, effectively replacing it. 
""" 
class WedgeClass(SetupClass): 
    def set_some_stuff(self): 
     self.something = 'foo' 
     pass # I'm a Python newbie, in too deep 

class UnitTests(unittest.TestCase): 

    @mock.patch(__module__+'.SetupClass') 
    def test_UUT(self, mock1): 
     wedge_class = WedgeClass() 
     mock1.side_effect = WedgeClass # <--- Ureka! 'side_effect' not 'return_value' was the ley! 

     uut = UUT() 
     self.assertTrue(uut.got_here)