Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems using User model in django unit tests

I have the following django test case that is giving me errors:

class MyTesting(unittest.TestCase):
    def setUp(self):
        self.u1 = User.objects.create(username='user1')
        self.up1 = UserProfile.objects.create(user=self.u1)

    def testA(self):
        ...

    def testB(self):
        ...

When I run my tests, testA will pass sucessfully but before testB starts, I get the following error:

IntegrityError: column username is not unique

It's clear that it is trying to create self.u1 before each test case and finding that it already exists in the Database. How do I get it to properly clean up after each test case so that subsequent cases run correctly?

like image 200
theycallmemorty Avatar asked May 15 '10 14:05

theycallmemorty


People also ask

How do you write unit test cases in Django?

Writing tests Django's unit tests use a Python standard library module: unittest . This module defines tests using a class-based approach. When you run your tests, the default behavior of the test utility is to find all the test cases (that is, subclasses of unittest.

What is the primary key of Django user model?

Django by default makes a primary key field on each model named " id ", with a type of AutoField .

What test framework does Django use?

The preferred way to write tests in Django is using the unittest module built-in to the Python standard library. This is covered in detail in the Writing and running tests document. You can also use any other Python test framework; Django provides an API and tools for that kind of integration.


3 Answers

setUp and tearDown methods on Unittests are called before and after each test case. Define tearDown method which deletes the created user.

class MyTesting(unittest.TestCase):     def setUp(self):         self.u1 = User.objects.create(username='user1')         self.up1 = UserProfile.objects.create(user=self.u1)      def testA(self):         ...      def tearDown(self):         self.up1.delete()         self.u1.delete() 

I would also advise to create user profiles using post_save signal unless you really want to create user profile manually for each user.

Follow-up on delete comment:

From Django docs:

When Django deletes an object, it emulates the behavior of the SQL constraint ON DELETE CASCADE -- in other words, any objects which had foreign keys pointing at the object to be deleted will be deleted along with it.

In your case, user profile is pointing to user so you should delete the user first to delete the profile at the same time.

like image 125
Davor Lucic Avatar answered Sep 27 '22 20:09

Davor Lucic


If you want django to automatically flush the test database after each test is run then you should extend django.test.TestCase, NOT django.utils.unittest.TestCase (as you are doing currently).

It's good practice to dump the database after each test so you can be extra-sure you're tests are consistent, but note that your tests will run slower with this additional overhead.

See the WARNING section in the "Writing Tests" Django Docs.

like image 22
Chris W. Avatar answered Sep 27 '22 20:09

Chris W.


Precisely, setUp exists for the very purpose of running once before each test case.

The converse method, the one that runs once after each test case, is named tearDown: that's where you delete self.u1 etc (presumably by just calling self.u1.delete(), unless you have supplementary specialized clean-up requirements in addition to just deleting the object).

like image 31
Alex Martelli Avatar answered Sep 27 '22 19:09

Alex Martelli