2013-05-30 16 views
6

Ho un modello e sto provando a testare la convalida senza richiamare il livello del database. Piuttosto che descrivere con le parole, inserirò solo qualche codice di esempio. Il problema qui è la relazione ForeignKey con Bar, che non è rilevante per ciò che sto cercando di testare ma mi impedisce di eseguire il test che voglio.Come utilizzare la libreria di simulazione per deridere un valore di Django ForeignKey?

In primo luogo, myapp/models.py:

from django.core.exceptions import ValidationError 
from django.db import models 


class BadFooError(ValidationError): 
    pass 


class Bar(models.Model): 
    description = models.CharField(max_length=20) 


class Foo(models.Model): 
    bar = models.ForeignKey(Bar) 

    a_value = models.IntegerField() 

    b_value = models.BooleanField() 

    def clean(self): 
     super(Foo, self).clean() 
     if self.b_value and self.a_value > 50: 
      raise BadFooError("No good") 

successivo, myapp/tests.py:

from unittest import TestCase 

from mock import MagicMock 

from . import models 


class SimpleTest(TestCase): 

    def test_avalue_bvalue_validation(self): 
     foo = models.Foo() 
     foo.a_value = 30 
     foo.b_value = True 
     foo.bar = MagicMock(spec=models.Bar) 
     self.assertRaises(models.BadFooError, foo.full_clean) 

    def test_method_2(self): 
     foo = models.Foo() 
     foo.a_value = 30 
     foo.b_value = True 
     foo.bar = MagicMock() 
     foo.__class__ = models.Bar 
     self.assertRaises(models.BadFooError, foo.full_clean) 

    def test_method_3(self): 
     foo = models.Foo() 
     foo.a_value = 30 
     foo.b_value = True 
     # ignore it and it will go away ...?? 
     self.assertRaises(models.BadFooError, foo.full_clean) 

Infine, l'uscita del python manage.py test myapp

EEE 
====================================================================== 
ERROR: test_avalue_bvalue_validation (myapp.tests.SimpleTest) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "~/sandbox/myapp/tests.py", line 14, in test_avalue_bvalue_validation 
    foo.bar = MagicMock(spec=models.Bar) 
    File "~/dsbx/local/lib/python2.7/site-packages/django/db/models/fields/related.py", line 408, in __set__ 
    instance._state.db = router.db_for_write(instance.__class__, instance=value) 
    File "~/dsbx/local/lib/python2.7/site-packages/django/db/utils.py", line 142, in _route_db 
    return hints['instance']._state.db or DEFAULT_DB_ALIAS 
    File "~/dsbx/local/lib/python2.7/site-packages/mock.py", line 658, in __getattr__ 
    raise AttributeError("Mock object has no attribute %r" % name) 
AttributeError: Mock object has no attribute '_state' 

====================================================================== 
ERROR: test_method_2 (myapp.tests.SimpleTest) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "~/sandbox/myapp/tests.py", line 21, in test_method_2 
    foo.bar = MagicMock() 
    File "~/dsbx/local/lib/python2.7/site-packages/django/db/models/fields/related.py", line 405, in __set__ 
    self.field.name, self.field.rel.to._meta.object_name)) 
ValueError: Cannot assign "<MagicMock id='31914832'>": "Foo.bar" must be a "Bar" instance. 

====================================================================== 
ERROR: test_method_3 (myapp.tests.SimpleTest) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "~/sandbox/myapp/tests.py", line 29, in test_method_3 
    self.assertRaises(models.BadFooError, foo.full_clean) 
    File "/usr/lib/python2.7/unittest/case.py", line 471, in assertRaises 
    callableObj(*args, **kwargs) 
    File "~/dsbx/local/lib/python2.7/site-packages/django/db/models/base.py", line 926, in full_clean 
    raise ValidationError(errors) 
ValidationError: {'bar': [u'This field cannot be null.']} 

---------------------------------------------------------------------- 
Ran 3 tests in 0.003s 

FAILED (errors=3) 
Creating test database for alias 'default'... 
Destroying test database for alias 'default'... 

Quindi la mia domanda è ... wat fare?

risposta

0

Bene, per ora ho semplicemente impostato la mia asserzione su self.assertRaises(models.BadFooError, foo.clean) (la differenza èal posto di foo.full_clean). Mentre questo funziona, non sembra ideale. Volevo testare la convalida come una scatola nera.

4

Nel mio test di unità, ho semplicemente assegnare _state ad una nuova istanza Mock, come in questo piccolo cambiamento per il primo test ad esempio unità:

def test_avalue_bvalue_validation(self): 
    foo = models.Foo() 
    foo.a_value = 30 
    foo.b_value = True 
    bar = Mock(spec=models.Bar) 
    bar._state = Mock() 
    foo.bar = bar 
    self.assertRaises(models.BadFooError, foo.full_clean) 

Tuttavia, per testare la vostra convalida come una scatola nera, I porterebbe il codice di convalida in un metodo separato sul modello che chiamerei dal metodo clean(). È quindi possibile unità testare questo codice di convalida in modo specifico. Dovrai comunque eseguire l'assegnazione _stage = Mock() in modo da poter creare l'istanza di Foo, ma almeno ridurrai le chiamate in Django.

Problemi correlati