0

I'm writing a test to validate the uniqueness of a field. In this test, I'm trying to validate that a Product's slug is unique. My initial test was the following:

from django.test import TestCase
from django.urls import reverse
from django.forms import ValidationError
from django.db.utils import IntegrityError
from rest_framework.test import APIClient
from rest_framework import status

from .factories import ProductFactory
from .models import Product
from .serializer import ProductSerializer

PRODUCTS_URL = reverse('product-list')

def create_product(**params):
    """ Helper function to create a new product """
    return Product.objects.create(**params)

class PrivateProductsTests(TestCase):

    def setUp(self):
        self.client = APIClient()
    
    
    def test_an_error_occurs_when_forcing_the_same_slug_for_different_products(self):

        product1 = ProductFactory.create(slug='')
        serializer1 = ProductSerializer(product1)
        product1_data = serializer1.data

        product1 = create_product(**product1_data)

        product2 = ProductFactory.create(slug=product1.slug)
        serializer2 = ProductSerializer(product2)
        product2_data = serializer2.data

        self.assertRaises(IntegrityError, create_product(**product2_data))

But it was failing with the following error:

django.db.utils.IntegrityError: duplicate key value violates unique constraint "products_product_slug_key" DETAIL: Key (slug)=(james-maxwell) already exists.

looking around I found the following question which provided an answer:

Fail on Testing IntegrityError UNIQUE constraint

now my test looks like:

def test_an_error_occurs_when_forcing_the_same_slug_for_different_products(self):

    product1 = ProductFactory.create(slug='')
    serializer1 = ProductSerializer(product1)
    product1_data = serializer1.data

    product1 = create_product(**product1_data)

    product2 = ProductFactory.create(slug=product1.slug)
    serializer2 = ProductSerializer(product2)
    product2_data = serializer2.data

    # there are two kinds of IntegrityError classes at play here, one
    # that's imported from the test and one raised by the db
    with self.assertRaises(IntegrityError) as raised:
        product2 = create_product(**product2_data)
    
    # print(type(raised.exception))
    self.assertEqual(IntegrityError, type(raised.exception))

but I wanted to go one step further an check that nothing had been stored in the system, so I modified my test to be (check the last 2 lines):

def test_an_error_occurs_when_forcing_the_same_slug_for_different_products(self):

product1 = ProductFactory.create(slug='')
serializer1 = ProductSerializer(product1)
product1_data = serializer1.data

product1 = create_product(**product1_data)

product2 = ProductFactory.create(slug=product1.slug)
serializer2 = ProductSerializer(product2)
product2_data = serializer2.data
print(product1.slug)
print(product2_data)

# self.assertRaises(IntegrityError, create_product(**product2_data))

# there are two kinds of IntegrityError classes at play here, one
# that's imported from the test and one raised by the db
with self.assertRaises(IntegrityError) as raised:
    product2 = create_product(**product2_data)

# print(type(raised.exception))
self.assertEqual(IntegrityError, type(raised.exception))

# verify there's only one item in the db
res = self.client.get(PRODUCTS_URL)
print(res.data)

After adding those two lines I'm getting the following error:

"An error occurred in the current transaction. You can't " django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.

How can I address this issue?

Bond Jerome
  • 95
  • 2
  • 12

0 Answers0