2013-08-13 2 views
18

Sto provando a utilizzare la libreria fittizia Python per correggere un task di Celery che viene eseguito quando un modello viene salvato nella mia app django, per verificare che venga chiamato correttamente.Utilizzo di simulazioni per correggere un'attività di sedano nei test di unità Django

In sostanza, il compito è definito all'interno myapp.tasks, e viene importato in cima alla mia models.py file in questo modo:

from .tasks import mytask

... e poi gira su save() all'interno del modello utilizzando mytask.delay(foo, bar). Fin qui tutto bene - funziona bene quando sto eseguendo Celeryd ecc.

Voglio costruire un test unitario che deride l'attività, solo per verificare che venga chiamato con gli argomenti corretti, e in realtà non lo fa prova a eseguire il compito di Celery in assoluto.

Quindi, nel file di test, ho qualcosa di simile all'interno di un TestCase norma:

from mock import patch # at the top of the file 

# ...then later 
def test_celery_task(self): 
    with patch('myapp.models.mytask.delay') as mock_task: 
     # ...create an instance of the model and save it etc 
     self.assertTrue(mock_task.called) 

... ma non è mai viene chiamato/è sempre false. Ho provato varie versioni (patching myapp.models.mytask, invece, e verificare se è stato chiamato mock_task.delay. Ho raccolto dai documenti di simulazione che il percorso di importazione è cruciale e googling mi dice che dovrebbe essere il percorso così come è visto all'interno del modulo sotto test (che sarebbe myapp.models.mytask.delay piuttosto che myapp.tasks.mytask.delay, se ho capito bene).

Dove sto andando male qui? c'è qualche difficoltà specifiche in patch compiti di sedano? Potrei patchare celery.task (che viene utilizzato come decoratore a mytask) invece?

+1

hai provato ad installare "CELERY_ALWAYS_EAGER = True", invece di deridere esso? – clsung

risposta

21

Il problema che si verifica non è correlato al fatto che si tratti di un compito di Celery.)

In particolare, è necessario scoprire quale vista o un altro file importa "MyTask" e patch là, in modo che la linea in questione sarebbe simile a questa:

with patch('myapp.myview.mytask.delay') as mock_task: 

C'è un po 'di sapore al questo qui:

http://www.voidspace.org.uk/python/mock/patch.html#where-to-patch

+0

Cheers! Devo ancora provarlo (il progetto è inattivo ora) ma lo proverò presto e segnerò come risposta. Mi sembra di ricordare di aver provato un po 'di variazioni sul tema che stai suggerendo, ma è del tutto possibile che il mio zucchero nel sangue fosse basso al momento ... :-) – Emil

+1

In realtà, lo sto facendo esattamente come suggerisci , come esemplificato nel codice della domanda ... Non riesco a farlo funzionare. Oh bene. – Emil

+0

La domanda sta applicando una patch al modello. Questo ha un cattivo odore, come sospetto che tu non stia usando "delay" nel modello, ma da qualche altra parte - forse una vista, quindi il mio codice patch (sopra) è leggermente diverso. –

18

il @task decoratore sostituisce la funzione con un oggetto Task (vedi documentation). Se prendi in giro l'attività, sostituirai l'oggetto (un po 'magico) Task con un MagicMock e non pianificherà affatto l'attività. Invece deridere il metodo dell'oggetto Taskrun(), in questo modo:

@override_settings(CELERY_ALWAYS_EAGER=True) 
@patch('monitor.tasks.monitor_user.run') 
def test_monitor_all(self, monitor_user): 
    """ 
    Test monitor.all task 
    """ 

    user = ApiUserFactory() 
    tasks.monitor_all.delay() 
    monitor_user.assert_called_once_with(user.key) 
+1

C'è una ragione per cui hai postato questa risposta, parola per parola, su due domande? –

+0

Sono informazioni piuttosto utili su questa domanda e l'altra. Non sono esattamente la stessa domanda però. –

+0

BTW se pensi che una risposta sia correlata e utile per due domande puoi contrassegnarne una come duplicata e qualcuno si prenderà cura di essa. Pubblica la stessa risposta è la cosa sbagliata da fare. –