Thanos
Thanos

Reputation: 1778

How to avoid duplicating test cases in Django?

I have written my test cases in two separate test files (e.g. test_1 and test_2). In both of test cases that I am testing my models I have code duplications because of similar processes.

For example, I need to login the user and test the credential.

Sample of code:

import test_data

from django.test import TestCase
from UserData.models import MyModel
from django.contrib.auth.models import User

class UserDataMyModelTestCalls(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.test_user = User.objects.create_user(test_data.test_user_data['user_name'],
                                                 test_data.test_user_data['email'],
                                                 test_data.test_user_data['password'])

    def test_faulty_login_credentials(self):
        self.client.login(username=test_data.faulty_user_data['user_name'], password=test_data.faulty_user_data['password'])
        response = self.client.get('/userdata/mymodelurl/', {})
        self.assertEqual(response.status_code, 403)

I am using a separate file with user credentials to avoid duplications again.

Sample of test_data file:

test_user_data = {'id': u'1',
                  'user_name': 'tempUsername',
                  'password': 'tempPassword',
                  'email': '[email protected]'}

Update: Adding the UserTests class that I want to use as a common class for all my test cases. I am defining and calling the test through the test_1.py like this:

import UserTests

from django.test import TestCase


class UserDataWayPointTestCalls(TestCase):

    testCasesObject = UserTests.UserDataTestCalls()
    test_user = testCasesObject.setUpTestData()
    response = testCasesObject.test_faulty_login_credentials()

My UserDataTestCalls class is defined like this:

import test_data

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


class UserDataTestCalls(TestCase):
    def __init__(self):
        self.test_user = None
        self.faulty_login_response = None

    def setUpTestData(self):
        self.client = User.objects.create_user(test_data.test_user_data['user_name'],
                                                  test_data.test_user_data['email'],
                                                  test_data.test_user_data['password'])
        self.client = Client()
        return self.client

    def test_faulty_login_credentials(self):
        self.client.login(username=test_data.faulty_user_data['user_name'],
                          password=test_data.faulty_user_data['password'])
        response = self.client.get('/userdata/mymodelurl/', {})
        return response

When I execute the code above I get IntegrityError: (1062, "Duplicate entry 'tempUsername' for key 'username'"). Temporarily I modify the username value to proceed and I get the following error AttributeError: 'UserDataTestCalls' object has no attribute '_testMethodName'.

I tried to create a separate class with name e.g. UserDataTestCalls and include the common parts of my test cases such as User.objects.create_user, self.client.login etc...

Unfortunately I end up getting errors that the database although it said Destroying test database for alias 'default'... on the next run I got username duplications e.g. Duplicate entry 'tempUsername' for key 'username' etc...

When I tried to overcome this problem by changing the username for testing purposes then I got another problem 'NoneType' object has no attribute 'login'.

Which it points that the self.client variable is not binded with the test_user that I am creating.

I tried to search online and find documentation on how to overcome my problem but all the documentation are pointing to use separate scripts for your tests individually, which I can understand if you have different test cases. In my case 90% of my test cases are exactly the same.

So I am sure there is a way to create a user in a separate class and create all my test cases in that class too, so I could call them from a separate test file(s) when I need them.

Can someone point me to the correct direction or provide some links with examples/documentation that I could read from?

Thank you in advance for your time and effort.

Upvotes: 0

Views: 1230

Answers (1)

Alasdair
Alasdair

Reputation: 308839

Try creating a common test class.

class CreateUserTestCase(TestCase):

    def setUpTestData(self):
        self.user = User.objects.create_user(
            test_data.test_user_data['user_name'],
            test_data.test_user_data['email'],
            test_data.test_user_data['password'],
        )

You want to assign the new user to self.user. Don't replace self.client which should be the test client, not the user. You don't need to do self.client = Client(), the Django test case will take care of this for you.

Then subclass the test case and add your tests.

class UserDataTestCalls(CreateUserTestCase):

    def test_faulty_login_credentials(self):
        self.client.login(
            username=test_data.faulty_user_data['user_name'],
            password=test_data.faulty_user_data['password'],
        )
        response = self.client.get('/userdata/mymodelurl/', {})
        return response

From your question, I wasn't sure if test_data is different for each class. If so, you'll have to change this slightly.

Upvotes: 2

Related Questions