5

I am trying to run the following unit test for my django project:

from django.test import TestCase
from django.contrib.auth.models import User
from CarbonEmissions import models

class DbTest(TestCase):
    #is called before each test case (e.g test_insertingUserProfiles)
    def setUp(self):
        self.user = User.objects.create(username='ppoliani')
        self.userProfile = models.UserProfile.objects.create(user=self.user, title='Mr', type='student', occupation='student')

    def test_insertingUserProfiles(self):
        """
            Testing the insertion of user profiles into our datbase 
        """
        self.assertEqual(self.user.get_profile().title,'Mr')

    #is called after each test case (e.g test_insertingUserProfiles)
    def tearDown(self):
        self.user.delete()
        self.userProfile.delete()

The test fails throwing the following error:

IntegrityError: duplicate key value violates unique constraint "CarbonEmissions_userprofile_user_id_key" DETAIL:  Key (user_id)=(1) already exists.

I can't understand what's wrong with that code.

4 Answers 4

2

The error message is telling you that the constraint "CarbonEmissions_userprofile_user_id_key" fails because, in some table, there's already a row that has user_id equal to 1.

To fix this, it might be easiest to look at the constraints and the data using pgAdminIII, which usually installs alongside PostgreSQL. Expand the table name to see the columns, constraints, and so on. Expand the constraints to see their names and properties. Right-click a table name, and select "View data" for options that let you browse the data.

Sign up to request clarification or add additional context in comments.

5 Comments

I realize that the user_id has a unique value constraint. But the fact is that i am running a unit test, therefore a new test database is created while the test is executing. As a result the tables are all empty.
@user512783: Odds favor your being mistaken. Look at the table. If you can't tell which line of your code is raising the error, trim your DBTest class until you isolate it.
@Catcall from the docs, "Separate, blank databases are created for the tests ... the test databases are destroyed when all the tests have been executed". If you're saying that pre-existing data (before the test run) is the problem, then no, it isn't. If you're saying that OP could kill the test to inspect the test database afterwards then of course that would work, but what information would that give beyond the IntegrityError?
@supervacuo: No, I'm saying the problem is in the OP's code, and I suggested one way to isolate the errant code. (Trim the code, and watch the table.) Seriously, the odds greatly favor programmer error over a PostgreSQL error or a Django error here, especially with that error message.
If the code does never specify the primary key value explicitly and the primary key is initialized regularly (implicitly with auto_increment) - then I would expect it to increment. The very weird behaviour is not that there is already data where there shouldn't be any (which is weird in itself but well) - but moreover that the primary key obviously is not incremented (correctly).
0

Maybe user profile object is already created by some code that listens to the post_save signal for User objects? If so then profile you are creating in the setUp function is a duplicate.

1 Comment

This would not explain why the primary key is not incremented if it is set to auto_increment.
0

You haven't posted the full stack trace (please do!) but I assume the error is on the line which creates the UserProfile object. The Django docs explicitly say that specifying a profile class in AUTH_PROFILE_MODULE will not automatically create a model of that type on adding a new user:

The method get_profile() does not create a profile if one does not exist. You need to register a handler for the User model's django.db.models.signals.post_save signal and, in the handler, if created is True, create the associated user profile:

So, as zifot suggests, there is probably some other code in your project creating a UserProfile. If it's doing so correctly, just remove your self.userProfile = models.UserProfile.objects.create(... line from setUp and access the profile via

self.user.get_profile()

Comments

0

This is an old issue, but I've encountered a similar problem recently.

I had a model, Quote, which had a field called reported. I recently changed this field to be private, and made a property to set and get it. (Because it has to update another model, and I didn't want to do this logic through signals or in the serializer.) When I changed it, I got the same error in my unit tests.

My model (simplified) was

class Quote(TimeStampedModel):

    _reported = models.BooleanField(
        default=False,
    )

    @property
    def reported(self):
        return self._reported

    @reported.setter
    def reported(self, value):
        self._reported = value
        if value:
            try:
                self.authorization_form.reported = True
                self.authorization_form.save()
            except AuthorizationForm.DoesNotExist:
                pass
        self.save()

My failing unit test was

def test_can_set_reported(self):
    quote = Quote.objects.create(
        reported=True,
    )

To make it pass, I changed it to

def test_can_set_reported(self):
    quote = Quote.objects.create(
        # reported=True,
    )
    quote.reported = True
    quote.save()

The problem, I suspect, is that I called the save() method when reported was set. So, the manager created the object and set the reported field (which called save), then tried to save the instance. This probably all happened within a single transaction, and so a duplicate key was introduced.

It would be worthwhile to look through the stack trace, I noticed two insert statements.

This is probably a sign that I should move this logic elsewhere. (Which I'll do.) But it was interesting to encounter this.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.