2013-05-30 23 views
6

Mam model i próbuję przetestować sprawdzanie poprawności bez wywoływania warstwy bazy danych. Zamiast opisywać słowami, podaję przykładowy kod. Kwestią tutaj jest relacja ForeignKey do paska, który nie ma związku z tym, co próbuję przetestować, ale powstrzymuje mnie przed przeprowadzeniem testu, który chcę.Jak użyć makiety do makiety wartości Django ForeignKey?

Najpierw 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") 

Następnie 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) 

Wreszcie, wyjście 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'... 

Więc moje pytanie brzmi ... wat zrobić?

Odpowiedz

0

Cóż, na razie po prostu zmieniłem moje potwierdzenie na self.assertRaises(models.BadFooError, foo.clean) (różnica to foo.clean zamiast foo.full_clean). Chociaż ten działa, nie wydaje się idealny. Chciałem przetestować walidację jako czarną skrzynkę.

4

W moich testów jednostkowych, po prostu przypisać _state do nowej instancji Mock, jak w tej małej zmiany w swoim pierwszym teście przykład jednostka:

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) 

Jednak, aby sprawdzić swoją walidację jako czarna skrzynka, I będzie ciągnąć kod walidacji do osobnej metody w twoim modelu, którą wywołuję z metody clean(). Następnie możesz jednostce przetestować ten kod walidacji. Nadal będziesz musiał wykonać zadanie _stage = Mock(), aby móc utworzyć instancję Foo, ale przynajmniej zminimalizujesz wywołania do Django.