使用模拟库

时间:2016-07-31 11:37:37

标签: django unit-testing django-models mocking

我正在尝试通过发布一些数据和模拟模型的save()方法来测试我的CreateView。

class BaseViewTest(TestCase):
   def setUp(self):
       self.user = UserFactory()
       self.factory = RequestFactory()

class MuayeneCreateViewTest(BaseViewTest):

   def test_get(self):
        request = self.factory.get(reverse('muayene:create'))
        request.user = self.user

        response = MuayeneCreateView.as_view()(request)

        self.assertEqual(response.status_code, 200)
        self.assertTrue('form' in response.context_data)
        self.assertTrue('muayene/muayene_form.html' in response.template_name)

    @patch('muayene.models.Muayene.save', MagicMock(name="save"))
    def test_post(self):
        hasta = HastaFactory()
        ilac1 = IlacFactory()
        ilac2 = IlacFactory()
        data = {
            'hasta': hasta.id,
            'tarih': str(datetime.date.today()),
            'yakinma': 'Kusma',
            'kullandigi_ilaclar': [ilac1.id, ilac2.id],
            'öntani_tani': 'Öntanı ve tanı',
            'öneri_görüsler': 'Öneri ve Görüşler',
            'özel_notlar': 'Özel notlar'
        }

        request = self.factory.post(reverse('muayene:create'), data)
        request.user = self.user

        response = MuayeneCreateView.as_view()(request)

        self.assertEqual(response.status_code, 302)

        self.assertTrue(Muayene.save.called)
        self.assertEqual(Muayene.save.call_count, 1)

以下是MuayeneCreateView

class MuayeneCreateView(LoginRequiredMixin, CreateView):
    login_url = '/login/'
    model = Muayene
    form_class = MuayeneCreateForm

和追溯:

ERROR: test_post (tests.test_muayene.MuayeneCreateViewTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib64/python3.5/unittest/mock.py", line 1157, in patched
    return func(*args, **keywargs)
  File "/home/egegunes/Dropbox/Programs/hastatakip/tests/test_muayene.py", line 153, in test_post
    response = MuayeneCreateView.as_view()(request)
  File "/usr/lib/python3.5/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/usr/lib/python3.5/site-packages/django/contrib/auth/mixins.py", line 56, in dispatch
    return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
  File "/usr/lib/python3.5/site-packages/django/views/generic/base.py", line 88, in dispatch
    return handler(request, *args, **kwargs)
  File "/usr/lib/python3.5/site-packages/django/views/generic/edit.py", line 256, in post
    return super(BaseCreateView, self).post(request, *args, **kwargs)
  File "/usr/lib/python3.5/site-packages/django/views/generic/edit.py", line 222, in post
    return self.form_valid(form)
  File "/usr/lib/python3.5/site-packages/django/views/generic/edit.py", line 201, in form_valid
    self.object = form.save()
  File "/usr/lib/python3.5/site-packages/django/forms/models.py", line 452, in save
    self._save_m2m()
  File "/usr/lib/python3.5/site-packages/django/forms/models.py", line 434, in _save_m2m
    f.save_form_data(self.instance, cleaned_data[f.name])
  File "/usr/lib/python3.5/site-packages/django/db/models/fields/related.py", line 1618, in save_form_data
    setattr(instance, self.attname, data)
  File "/usr/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 480, in __set__
    manager = self.__get__(instance)
  File "/usr/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 468, in __get__
    return self.related_manager_cls(instance)
  File "/usr/lib/python3.5/site-packages/django/db/models/fields/related_descriptors.py", line 751, in __init__
    (instance, self.source_field_name))
ValueError: "<Muayene: ID: None - 2016-07-31 - Bob Baz>" needs to have a value for field "muayene" before this many-to-many relationship can be used.

我无法弄清楚导致此错误的原因。其他模型使用Muayene实例,但除非我尝试使用此实例创建其中一个模型,否则IMO不会显示此错误。

修改

Muayene型号:

class Muayene(models.Model):
    hasta = models.ForeignKey(
        'hasta.Hasta', 
        on_delete=models.CASCADE
    )
    tarih = models.DateField(
        default = timezone.now
    )
    yakinma = models.TextField(
        max_length = 255,
        blank = True, 
        null = True
    )
    kullandigi_ilaclar = models.ManyToManyField(
        Ilac,
        blank = True
    )
    baki = models.TextField(
        max_length = 255,
        blank = True, 
        null = True
    )
    öntani_tani = models.TextField(
        max_length = 255,
        blank = True, 
        null = True
    )
    öneri_görüsler = models.TextField(
        max_length = 255,
        blank = True, 
        null = True
    )
    özel_notlar = models.TextField(
        max_length = 255,
        blank = True, 
        null = True
    )

    def __str__(self):
        tarih = str(self.tarih)
        hasta = str(self.hasta.ad + " " +  self.hasta.soyad)
        pk = str(self.pk)
        return "ID: " + pk + " - " + tarih + " - " + hasta
    def get_absolute_url(self):
        return reverse('muayene:detail', kwargs={'pk':self.pk})
    def was_today(self):
        today = datetime.date.today()
        if  today - datetime.timedelta(days=1) <= self.tarih <= today:
            return True
        else:
            return False

Muayene相关的模型:

class Recete(models.Model):
    hasta = models.ForeignKey(
        'hasta.Hasta', 
        on_delete=models.CASCADE
    )
    muayene = models.ForeignKey(
        'muayene.Muayene',
        on_delete=models.CASCADE,
    )
    tarih = models.DateField(
        default = timezone.now        
    )
    ilaclar = models.ManyToManyField(Ilac)

    def __str__(self):
        return str(self.tarih)
    def get_absolute_url(self):
        return reverse('muayene:recete-detail', kwargs={'pk':self.pk})

class Rapor(models.Model):
    hasta = models.ForeignKey(
        'hasta.Hasta', 
        on_delete=models.CASCADE
    )
    muayene = models.ForeignKey(
        'muayene.Muayene',
        on_delete=models.CASCADE
    )
    tarih = models.DateField(
        default = timezone.now        
    )
    tani = models.CharField(
        blank = True,
        null = True,
        max_length = 255        
    )
    gun = models.PositiveSmallIntegerField(
        default = 1        
    )
    def __str__(self):
        return str(self.hasta)
    def get_absolute_url(self):
        return reverse('muayene:rapor-detail', kwargs={'pk':self.pk})

class LaboratuvarIstek(models.Model):
    hasta = models.ForeignKey(
        'hasta.Hasta', 
        on_delete=models.CASCADE
    )
    muayene = models.ForeignKey(
        'muayene.Muayene',
        on_delete=models.CASCADE,
    )
    tarih = models.DateField(
        default = timezone.now        
    )
    istekler = models.ManyToManyField(Laboratuvar)

    def __str__(self):
        return str(self.hasta)
    def get_absolute_url(self):
        return reverse('muayene:lab-detail', kwargs={'pk':self.pk})

1 个答案:

答案 0 :(得分:0)

您实际上可以在追溯中看到失败的原因:

File "/usr/lib/python3.5/site-packages/django/forms/models.py", line 452, in save
    self._save_m2m()

这是因为您的视图并未直接调用模型的保存方法。相反,它获取用于模型的表单(或创建一个带有工厂的表单)并调用表单的保存方法。您可以在django.forms.models.BaseModelForm.save处查看此方法。因此,如果您真的想要计算模型实例上的调用并且不想测试失败,那么您也应该模拟django.forms.models.BaseModelForm._save_m2m,因为它会以表单的保存方法调用。