Django Сбой теста CreateView - PullRequest
       5

Django Сбой теста CreateView

0 голосов
/ 27 февраля 2020

Моя конфигурация ниже (django 3.02):

Модели:

class Assets(models.Model):
    assettag = models.CharField()
    ...

class Item(models.Model):
    asset = models.OneToOneField('Assets')
    ...

    def __str__(self):
        return (f"{self.rfid_tag}" + " - " + f"{self.asset.assettag}")

class Comments(models.Model): # I know, it should not be plural.
    item = models.ForeignKey('Item',
                             default=None,
                             null=True,
                             on_delete=models.CASCADE,
                             )
    text = models.TextField()
    ...

Форма:

class ItemInsertForm(forms.ModelForm):
    rfid_tag = forms.CharField(label='RFID Tag',
                               widget=forms.TextInput(attrs={"placeholder":"96 bit EPC code",
                                                             "pattern":"^[a-fA-F0-9]{24}$",
                                                             "size":"25",
                                                             "id":"rfid_tag",
                                                             }
                                                      )
                               )
    asset = forms.CharField(label='AssetTag',
                            widget=forms.TextInput(attrs={"placeholder":"Item Inventory Tag",
                                                          "pattern":"{some regex}",
                                                          "size":"25",
                                                          "id":"asset",
                                                          }
                                                   )
                            )

    comments = forms.CharField(label='Comments',
                               required=False,
                               widget=forms.Textarea(attrs={"rows":5,
                                                            "cols":50,
                                                            "id":"comments",
                                                           }
                                                    )
                              )

    class Meta:
        model = Item
        fields = [
            'rfid_tag',
            'asset',
            'image',
            'date',
        ]


    def clean_rfid_tag(self, *args, **kwargs):
        return self.cleaned_data.get("rfid_tag").lower()

    def clean_asset(self, *args, **kwargs):
        AssetTag = self.cleaned_data.get("asset")
        try:
            _asset = Assets.objects.get(assettag = AssetTag)
        except Assets.DoesNotExist:
            raise forms.ValidationError("Asset does not exist !")
        self.Asset = _asset
        return self.Asset

Вид:

class InsertView(SuccessMessageMixin, AuditMixin, generic.CreateView):
    template_name = '{some template}'
    success_message = "Item succesfully created"
    form_class = ItemInsertForm

    def form_valid(self, form):
        item = form.save(commit=False)
        _comment = form.cleaned_data.get('comments')
        item = form.save()
        if _comment:
            item.comments_set.create(text =_comment)
        self.log_insert(item)
        return super().form_valid(form)

Тест:

class TestViews(TestCase):
    @classmethod
    def setUpTestData(cls) -> None:
        # create dummy assets
        cls.asset = Assets.objects.create(assettag="{some assettag #1}",)
        cls.asset2 = Assets.objects.create(assettag="{some assettag #2}")
        # create dummy item
        cls.item = Item.objects.create(rfid_tag='abcdef012345678900000000', asset=cls.asset)

    def setUp(self) -> None:
        self.client = Client()
        self.insert_url = reverse('inventory:insert')

    def test_insert_POST_valid(self):
        response = self.client.post(self.insert_url,
                                    data = {'rfid_tag':'abcdef012345678900000001',
                                            'asset':'{some assettag #2}',}
                                    )
        new_item = Item.objects.get(rfid_tag="abcdef012345678900000001")
        self.assertEqual(response.status_code, 302)
        self.assertTrue(isinstance(new_item,Item))
        self.assertEqual(Item.objects.filter(rfid_tag="abcdef012345678900000001").count(),1)
        self.assertEqual(self.asset2.item, new_item)
        self.assertFalse(Comments.objects.all())

    def test_insert_POST_comment(self):
        response = self.client.post(self.insert_url,
                                    data = {'rfid_tag':'abcdef012345678900000001',
                                            'asset':'{some assettag #2}',
                                            'comments':'Test comment.',
                                            }
                                    )
        new_item = Item.objects.get(rfid_tag="abcdef012345678900000001")
        self.assertEqual(response.status_code, 302)
        self.assertTrue(isinstance(new_item,Item))
        self.assertEqual(Item.objects.filter(rfid_tag="abcdef012345678900000001").count(),1)
        self.assertEqual(self.asset2.item, new_item)
        self.assertTrue(isinstance(Comments.objects.get(text='Test comment.'), Comments))
        self.assertEqual(Comments.objects.get(text='Test comment.'),
                         new_item.comments_set.first())

Если я выполню эти тесты, test_insert_POST_valid не будет выполнен из-за ошибки подтверждения:

AssertionError: ! =

Я вставил несколько операторов печати по всему коду:

    # this was placed first in both tests, before the POST request
    items = Item.objects.all()
    for item in items:
        print("Item:",item.id, " - ", item)

    # and then again, after each POST request

Я заметил, что при первом запуске печати будет выведен только один Item объект (это верно для обеих функций):

Item: 1 - abcdef012345678900000009 - {some assettag # 1}

но при втором запуске (после отправки запроса POST и создания нового элемента):

Для test_insert_POST_comment результат:

Элемент: 1 - abcdef012345678900000009 - {некоторый активаг # 1}
Item: 2 - abcdef012345678900000001 - {некоторый активаг # 2}

В то время как для test_insert_POST_valid результат равен:

Предмет: 1 - abcdef012345678900000009 - {некоторый активаг # 1}
Предмет: 3 - abcdef012345678900000001 - {Некоторый актив # 2}

Если я сделаю print("Asset Item:", self.asset2.item.id, " - ", self.asset2.item) в функции test_insert_POST_valid (по какой-то причине этот тест выполняется вторым) он выдаст:

Элемент актива: 2 - abcdef012345678900000001 - {some assettag # 2}

Я не понимаю, как это происходит. Item.objects.all() вернет только один объект (abcdef012345678900000000), в то время как объект Asset все еще поддерживает связь с вымышленным вторым Item объектом, который не существует.

Я подозревал, что test_insert_POST_valid фактически не создает никакого объекта, поскольку self.asset2 уже имеет отношение Item через отношение OneToOne, но это не так. Если я изменю значение rfid_tag на abcdef012345678900000002 (или что-то еще), он создаст новый Item, но self.asset2.item все равно будет указывать на abcdef012345678900000001.

В чем причина этой проблемы, и может ли это Я это решаю? (Помещение self.asset2.item = None перед отправкой данных не поможет. Новые отношения не будут созданы.)

Редактировать: я мог бы переместить cls.asset2 = Assets.objects.create(assettag="{some assettag #2}") в методе setUp и он будет создаваться перед каждым тестом, но у меня есть еще несколько логинов c, в зависимости от этого мне тоже придется его перенести. Предпочтительный способ - оставить его в setUpTestdata, чтобы он работал только один раз.

1 Ответ

0 голосов
/ 28 февраля 2020

Я нашел простое решение: добавить self.asset2.refresh_from_db() в методе setUp. Это перезагрузит каждое поле этой модели из базы данных перед выполнением каждого теста.

...