2012-08-31 2 views
5

Ho un gestore di cliente per un modello di Django, che ridefinisce il metodo create per salvare anche alcuni oggetti correlati:Come si prende in giro un metodo RelatedManager in Django?

class CustomManager(models.Manager): 
    def create(self, amount, user, description): 
     txn = self.get_query_set().create(user, description) 
     txn.budget_transactions.create(amount) 
     return txn 

La mia domanda è: come faccio a prendere in giro il chiamata a txn.budget_transactions.create a sollevare un'eccezione?

L'attributo budget_transactions dell'oggetto txn è un'istanza di django.db.models.fields.related.RelatedManager. Usando mock.patch per deridere questa classe non funziona come è dichiarato dinamicamente - non può essere importato direttamente.

Qualcuno sa come fare?

+0

Stai usando la libreria Mock? Vuoi usare un context-manager di patch o un decoratore? – santiagobasulto

+0

Sono felice di utilizzare la libreria di simulazione se è in grado di risolvere questo problema. Come ho detto sopra, l'uso di 'mock.patch' nel modo convenzionale non funziona a causa della dichiarazione dinamica delle classi RelatedManager. – DavidWinterbottom

risposta

5

La ragione per cui non è possibile impostare il RelatedManager su un oggetto fittizio è perché django ha sostituito il metodo impostato su sull'oggetto. Quindi, mentre sembra che il mock sia impostato correttamente perché non ci sono lamentele, in realtà sta impostando automaticamente budget_transactions sul RelatedManager. Quindi, se hai davvero bisogno di restituire una simulazione, dovrai sostituire il metodo con il metodo che restituisce il RelatedManager e restituire invece un oggetto fittato.

dovrebbe finire lookig somthing come:

@mock.patch('django.db.models.fields.related.ForeignRelatedObjectsDescriptor.__get__') 
def test_campaign_cancel(self, mock_manager): 
    mock_manager.return_value = mock.MagicMock() 
    mock_manager.return_value.create = Exception('Boom!') 

Detto ci sono molte insidie ​​di questo approccio, poiché sarà override un metodo nucleo django e ora TUTTE RelatedManagers restituirà un oggetto deriso. Da quello che ho vissuto finora è probabilmente più facile esplorare altre opzioni.

+0

Ho dovuto prendere in giro 'django.db.models.fields.related.ReverseManyRelatedObjectsDescriptor .__ set__', ma lo stesso approccio generale. – AlanSE