I'm working on a project with Django as framework and poetry as manager. Running some tests I found some problems with my viewsets, but I don't know exactly where it is. That's the error traceback:
poetry run python3 manage.py test tests/
Found 6 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F.F...
======================================================================
FAIL: test_create_order (test_orderviewset.TestOrderViewSet)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/mateus/Área de Trabalho/EBAC/Back-end/BookStore/tests/test_orderviewset.py", line 47, in test_create_order
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
AssertionError: 400 != 201
======================================================================
FAIL: test_create_product (test_productviewset.TestProductViewSet)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/mateus/Área de Trabalho/EBAC/Back-end/BookStore/tests/test_productviewset.py", line 52, in test_create_product
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
AssertionError: 400 != 201
----------------------------------------------------------------------
Ran 6 tests in 0.102s
FAILED (failures=2)
Destroying test database for alias 'default'...
My test file:
class TestOrderViewSet(APITestCase):
client = APIClient()
def setUp(self):
self.category = CategoryFactory(title='comida')
self.product = ProductFactory(title='CARNE', price=20.0, category=[self.category,])
self.order = OrderFactory(product=[self.product,])
def test_create_order(self):
product = ProductFactory()
user = UserFactory()
order_data = json.dumps({
'products_id': [product.id,],
'user': user.id
})
response = self.client.post(reverse('order-list', kwargs={'version': 'v1'}), data=order_data,
content_type='application/json')
import pdb
pdb.set_trace()
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
I also made some factories using factory_boy to create some fake data to tests:
import factory
from django.contrib.auth.models import User
from .models import *
class UserFactory(factory.django.DjangoModelFactory):
username = factory.Faker('pystr')
email = factory.LazyAttribute(lambda x: '%[email protected]' % x.username)
class Meta:
model = User
class CategoryFactory(factory.django.DjangoModelFactory):
title = factory.Faker('pystr')
slug = factory.Faker('pystr')
description = factory.Faker('pystr')
active = factory.Iterator([True, False])
class Meta:
model = Category
class ProductFactory(factory.django.DjangoModelFactory):
title = factory.Faker('pystr')
price = factory.Faker('pyfloat')
category = factory.LazyAttribute(CategoryFactory)
@factory.post_generation
def category(self, create, extracted, **kwargs):
if not create:
return
if extracted:
for category in extracted:
self.category.add(category)
class Meta:
model = Product
skip_postgeneration_save = True
class OrderFactory(factory.django.DjangoModelFactory):
user = factory.SubFactory(UserFactory)
@factory.post_generation
def product(self, create, extracted, **kwargs):
if not create:
return
if extracted:
for product in extracted:
self.product.add(product)
class Meta:
model = Order
skip_postgeneration_save = True
And the serializers I created:
class ProductSerializer(serializers.ModelSerializer):
category = CategorySerializer(required=True, many=True)
category_id = serializers.PrimaryKeyRelatedField(queryset=Category.objects.all(), write_only=True, many=True)
class Meta:
model = Product
fields = ['title', 'description', 'price', 'active', 'category', 'category_id']
extra_kwargs = {'category': {'required': False}}
def create(self, validated_data):
category_data = validated_data.pop('category_id')
product = Product.objects.create(**validated_data)
for category in category_data:
product.category.add(category)
return product
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = [
'title',
'slug',
'description',
'active',
]
extra_kwargs = {'slug': {'required': False}}
class OrderSerializer(serializers.ModelSerializer):
product = ProductSerializer(required=True, many=True)
products_id = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all(), write_only=True, many=True)
total = serializers.SerializerMethodField()
# Model function method
def get_total(self, instance):
total = sum([product.price for product in instance.product.all()])
return total
def create(self, validated_data):
products_data = validated_data.pop('products_id')
user_data = validated_data.pop('user')
order = Order.objects.create(user=user_data)
for product in products_data:
order.objects.add(product)
return order
class Meta:
model = Order
fields = ['product', 'total', 'user', 'products_id']
extra_kwargs = {'product': {'required': True}}
Finally, my model's file:
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
description = models.TextField(max_length=200, blank=True, null=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.title
class Product(models.Model):
title = models.CharField(max_length=200)
description = models.TextField(max_length=500, blank=True, null=True)
price = models.FloatField(null=False)
active = models.BooleanField(default=True)
category = models.ManyToManyField(Category, blank=True)
def __str__(self):
return self.title
class Order(models.Model):
product = models.ManyToManyField(Product, blank=False)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=False)
def __str__(self):
return self.customer.name
I try to add this field in a field 'extra_kwargs' (no success with that), the message persists. Then I checked if it was declared in it's respective fields. It was, but, somehow, my tests don't send that data using Factory, and post this in response content:
b'{"product":["This field is required."]}'