2012-03-18 15 views
5

Avere uno strano problema con Python e PyMongo. Il test ha esito positivo o negativo in modo casuale:Test non testati su Python MongoDB fallisce casualmente

import unittest 
from pymongo import Connection 

from tractor import Tractor 




class TestTractor(unittest.TestCase): 
    def setUp(self): 
     self.tractor = Tractor(1) 

     self.mongo = Connection() 
     self.db = self.mongo.tractor 

     self.db.classes.remove({'name': {'$regex':'^test_'}}) 

     self.action_class_id = self.db.classes.insert({'name': 'test_action', 
                 'metaclass': 'action'}) 
     self.object_class_id = self.db.classes.insert({'name': 'test_object', 
                 'metaclass': 'object'}) 


    def tearDown(self): 
     self.tractor = None 



    def test_create_class(self): 
     cid1 = self.tractor.create_action_class('test_create_action_class') 
     cid2 = self.tractor.create_object_class('test_create_object_class') 

     self.assertNotEqual(cid1, None) 
     self.assertNotEqual(cid2, None) 

     action_obj = self.db.classes.find_one({'_id': cid1}) 
     object_obj = self.db.classes.find_one({'_id': cid2}) 

     self.assertNotEqual(cid1, cid2) 
     self.assertEqual(action_obj['_id'], cid1) 
     self.assertEqual(object_obj['_id'], cid2) 

     self.assertEqual(action_obj['name'], 'test_create_action_class') 
     self.assertEqual(object_obj['name'], 'test_create_object_class') 

Classe in fase di test:

from pymongo import Connection 
from pymongo.objectid import ObjectId 



class Tractor(object): 
    def __init__(self, uid): 
     self.uid = uid 
     self.mongo = Connection() 
     self.db = self.mongo.tractor 


    # Classes 

    def create_action_class(self, name): 
     return self.db.classes.insert({'name': name, 
             'attributes': [], 
             'metaclass': 'action'}) 

    def create_object_class(self, name): 
     return self.db.classes.insert({'name': name, 
             'attributes': [], 
             'metaclass': 'object'}) 

comportamento casuale:

[email protected] ~/projects/traction/tractor $ python -m unittest discover 
......ssEssssssssss 
====================================================================== 
ERROR: test_create_class (tests.test_tractor.TestTractor) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/home/silver/projects/traction/tractor/tests/test_tractor.py", line 64, in test_create_class 
    self.assertEqual(action_obj['_id'], cid1) 
TypeError: 'NoneType' object is not subscriptable 

---------------------------------------------------------------------- 
Ran 19 tests in 0.023s 

FAILED (errors=1, skipped=12) 

...

[email protected] ~/projects/traction/tractor $ python -m unittest discover 
......ss.ssssssssss 
---------------------------------------------------------------------- 
Ran 19 tests in 0.015s 

OK (skipped=12) 

Questi due risultati accada in modo casuale per lo stesso test di rieseguire il t est senza cambiare nulla né nella classe né nel test.

Tutto questo viene eseguito sulla mia macchina e sono certo che durante l'esecuzione del test nessun altro armerà né con MongoDB né con il codice.

Cosa dà?

+0

Forse hai una condizione di gara. Se stai ricevendo 'None' per la tua ricerca, sarebbe saggio lanciare questo test unitario in un debugger e tracciare esattamente cosa ha causato il colpo. – MrGomez

+0

@MrGomez, pensi che insert() ritorni prima che l'oggetto sia effettivamente inserito, e un find() che segue rapidamente non lo trovi prima? Ma poi insert() non tornerebbe, no? – sssilver

+0

Questa è almeno la mia teoria. Buona fortuna nel debugging. – MrGomez

risposta

4

Ho il forte sospetto che il problema qui sia che non state usando la modalità "sicuro" per le vostre scritture.

Per impostazione predefinita MongoDB utilizza la modalità "Ignora e dimentica". Ciò significa che il comando di inserimento viene inviato al server, ma il driver non controlla le risposte del server.

Quando si passa alla modalità "sicuro", il driver invierà il comando di inserimento e invierà quindi un secondo comando getLastError. Questo secondo comando verrà restituito quando il server ha effettivamente impegnato la scrittura.

Anche in questo caso, per impostazione predefinita si sta utilizzando la modalità "Ignora e dimentica", quindi qui c'è davvero una potenziale condizione di competizione. Per i test unitari è necessario eseguire la modalità "sicuro".

La firma della funzione per l'inserimento è definita here. Tuttavia, dovresti anche essere in grado di apportare la modifica a livello di connessione in modo che ogni connessione al DB utilizzi la modalità "sicura" per impostazione predefinita.

+0

Assolutamente !! Questo ha risolto tutto e risolto tutto il problema. Questo mi ha dato un debug difficile. – sssilver

Problemi correlati