Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit tests fail after a Django upgrade

I am trying to bring a Django project from version 1.8 to 1.11. Pretty much everything seems to work fine except unit tests. We have a base test class inheriting from Django TestCase with a Tastypie mixin. The base class has some code in the setUp() like this

class BaseApiTest(ResourceTestCaseMixin, django.test.TestCase):
    def setUp(self):
        super().setUp()
        self.username = "secret_user"
        self.password = "sekret"
        self.email = "[email protected]"
        self.first_name = "FirstName"
        self.last_name = "LastName"
        self.user = User.objects.create_superuser(
            self.username,
            self.username,
            self.password
        )

And the app specific tests would inherit the base test and do something like

class TheAPITest(BaseApiTest):
    def setUp(self):
        super().setUp()
        # more setup goes here

So, under Django 1.8.x this works fine. But under 1.11.x all of these give me an error on the User.objects.create_superuser() line.

django.db.utils.InterfaceError: connection already closed

I have been going through the release notes, but there is just too much stuff that has happened between 1.8 and 1.11. Is there something simple that I am missing?

like image 221
Mad Wombat Avatar asked Aug 04 '17 21:08

Mad Wombat


2 Answers

I have uncovered multiple issues with my unit test coverage, but to answer the question I posted, two separate issues were causing the errors I described.

Django 1.11 is stricter about its model instance creation and we had some legacy test code that was not updated to new model structure. For example, if you take the default User model, in Django 1.8 you can do

from django.contrib.auth.models import User    
User.objects.create(username="something", password="something", something="something")

But in Django 1.11 it will raise an exception "TypeError: 'something' is an invalid keyword argument for this function".

And the second issue is that Django TestCase wraps test cases in two separate atomic blocks. This helps with keeping class level setup separate from instance level setup, but it also introduces a subtle problem. If a test crashes with a database error you never see the error because it happens in the test level atomic and not in the class level atomic. The test level atomic fails and database connection gets dropped. After that every test is going to fail with the exact django.db.utils.InterfaceError: connection already closed error I was seeing. Switching from TestCase to TransactionTestCase caused a lot of these problems to be exposed directly in the test output.

like image 118
Mad Wombat Avatar answered Nov 10 '22 22:11

Mad Wombat


It may be useful to have the error trace. But for the moment in the code I see this error:

   self.user = User.objects.create_superuser(
                self.username,
                self.username, **this should be self.email**
                self.password
            )
like image 3
wololoooo Avatar answered Nov 10 '22 21:11

wololoooo