jazzband / django-taggit

Simple tagging for django
https://django-taggit.readthedocs.io
BSD 3-Clause "New" or "Revised" License
3.31k stars 623 forks source link

How to write test with taggable manager #701

Open convers39 opened 3 years ago

convers39 commented 3 years ago

I am writing tests and cannot figure out how to test with taggit field.

Here is my model:

class Product(models.Model):
    name = models.CharField(_("name"), max_length=50)
    slug = models.SlugField(_("slug"), max_length=50,
                            unique=True, null=True, blank=True)
    summary = models.CharField(_("summary"), max_length=250)
    detail = RichTextField(blank=True, null=True)
    unit = models.CharField(_("unit"), max_length=50)
    #...
    tags = TaggableManager(_("tags"))

And I am using factory_boy for testing, but seems tags cannot be used.

class ProductFactory(DjangoModelFactory):
    class Meta:
        model = Product

    name = factory.Sequence(lambda n: 'awesome item %d' % n)
    summary = factory.Faker('sentence')
    unit = 1
    price = 500
    brand = factory.Faker('company')
    tags = TaggableManager()
    # tags = ['buff']
    category = factory.SubFactory(CategoryFacotry)
    origin = factory.SubFactory(OriginFacotry)
    spu = factory.SubFactory(SpuFacotry)

By default, factory boy will use the fields in the related model, however no matter I leave tags as blank, or assign it again with TaggableManager, I got an AttributeError.

ERROR: setUpClass (shop.tests.test_views.TestShopDetailView)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/site-packages/django/test/testcases.py", line 1123, in setUpClass
    cls.setUpTestData()
  File "/usr/src/app/apps/shop/tests/test_views.py", line 126, in setUpTestData
    cls.sku.tags.add('awesome')
AttributeError: 'TaggableManager' object has no attribute 'add'

Is that possible to use taggit with factory boy? Or are there any other methods to write a test with taggit? Very little information in the docs and StackOverflow about testing with taggit, really appreciate your help.

2019342a commented 2 years ago

Hi, you could perhaps use post-generation hooks.

In your example it would be something like

class ProductFactory(DjangoModelFactory):
   # Rest of the stuff

    @post_generation
    def tags(self, create, extracted, **kwargs):
        if not create:
            return

        if extracted:
            self.tags.add(*extracted)

Then you just pass it a list of tags when you instantiate the object

...
product = ProductFactory(tags=['buff'])
...