2013-01-17 8 views
7

Sto tentando di scrivere un test di unità per di __init__ una classe:Come faccio a simulare un __init__ di una superclasse? Creare un attributo contenente un oggetto fittizio per un test unitario?

def __init__(self, buildNum, configFile = "configfile.txt"): 
     super(DevBuild, self).__init__(buildNum, configFile) 

     if configFile == "configfile.txt": 
      self.config.MakeDevBuild() 

L'attributo di configurazione è impostato dal super __init__. Sto usando mock e voglio che l'attributo config sia un oggetto mock. Tuttavia, non sono stato in grado di capire come effettivamente farlo accadere. Ecco il meglio che ho potuto venire con per il test:

def test_init(self): 
     with patch('DevBuild.super', create=True) as mock_super: 
      mock_MakeDevBuild = MagicMock() 
      mock_super.return_value.config.MakeDevBuild = mock_MakeDevBuild 

      # Test with manual configuration 
      self.testBuild = DevBuild("42", "devconfigfile.txt") 
      self.assertFalse(mock_MakeDevBuild.called) 

      # Test with automated configuration 
      self.testBuild = DevBuild("42") 
      mock_MakeDevBuild.assert_called_once_with() 

Tuttavia, questo non funziona - ho un errore:

Error 
Traceback (most recent call last): 
    File "/Users/khagler/Projects/BuildClass/BuildClass/test_devBuild.py", line 17, in test_init 
    self.testBuild = DevBuild("42") 
    File "/Users/khagler/Projects/BuildClass/BuildClass/DevBuild.py", line 39, in __init__ 
    self.config.MakeDevBuild() 
AttributeError: 'DevBuild' object has no attribute 'config' 

Chiaramente non sto impostando la configurazione degli attributi correttamente , ma non ho idea dove esattamente dovrei impostarlo. O del resto, se quello che voglio fare è anche possibile. Qualcuno può dirmi cosa devo fare per farlo funzionare?

+0

Un'osservazione: il il valore di ritorno di 'super' non è un oggetto che ha un attributo' config', ma piuttosto un oggetto che ha un metodo '__init__' che aggiungerà un attributo' config' al suo argomento. – chepner

+0

E 'l'intero '__init__'? Se lo è, aggiungerà solo self.config.MakeDevBuild se non viene passato il nome del file di configurazione, cosa che si fa nel test. – jlujan

risposta

16

Non è possibile simulare __init__ impostandolo direttamente - vedere _unsupported_magics in mock.py.

Quanto a ciò che si può fare, si può prendere in giro __init__ facendolo passare per rattoppare, in questo modo:

mock_makeDevBuild = MagicMock() 
def mock_init(self, buildNum, configFile): 
    self.config = MagicMock() 
    self.config.MakeDevBuild = mock_makeDevBuild 

with patch('DevBuild.SuperDevBuild.__init__', new=mock_init): 
    DevBuild("42") 
    mock_makeDevBuild.assert_called_once_with() 

dove SuperDevBuild è una classe base di DevBuild.

Se davvero si vuole prendere in giro super(), si può forse fare una classe e quindi associare __init__ di opporsi manualmente, come

mock_makeDevBuild = MagicMock() 
def get_mock_super(tp, obj): 
    class mock_super(object): 
     @staticmethod 
     def __init__(buildNum, configFile): 
      obj.config = MagicMock() 
      obj.config.MakeDevBuild = mock_makeDevBuild 
    return mock_super 
with patch('DevBuild.super', create=True, new=get_mock_super): 
    DevBuild("42") 
    mock_makeDevBuild.assert_called_once_with() 

che funziona, ma è abbastanza brutto ..

+1

Grazie, il primo approccio ha fatto ciò di cui avevo bisogno. – khagler

Problemi correlati