How To Use Autofixtures in Unit Tests

by Owais Mushtaq

In the last blog we learnt how to write UnitTests using TestCase, but what do we do, if we have to load data several times during testing in a controlled manner. Django Autofixtures aim to provide a simple way of loading huge mass of randomly generated test data into your development database.

It is named autofixture because of its similarity with django’s fixtures. Usually you add test data through admin to see how your site looks with non static pages. You export data by using dumpdata to send it to your colleagues or to preserve it before you make a manage.py reset app and so on. Your site gets more and more complex and adding test data gets more and more annoying. You can use a management command to load test data through command line if you want to test how templates will look when there is random data in models.

Installation & How to use Management Command

Please visit https://github.com/gregmuellegger/django-autofixture

Using Autofixtures as Tool for UnitTests

from django.test import TestCase

# Api

from dbank.api.canon import PersonModelListResource

#Modals

from dbank.models import PersonModel

#Django AutoFixtures

from dbank.autofixtures import PersonModelAutoFixture

class TestPersonModelListResource(TestCase):

 @classmethod

 def setUpClass(cls):

 cls.canon = PersonModelListResource()

 def test_get_match(self):

 """Matches persons aganist the first name, last name or email provided.

 """

 # Create a person using fixture

 data = PersonModelAutoFixture(PersonModel, data={'name_first': ';John;', 

 'name_last': ';Doe;','email': ';jdoe@testemail.com;'} , generate_fk=True) .create(1) #creates a single person with autofixture

 record = self.canon._get(name_first='John',name_last='Doe',

 email='jdoe@testemail.com', match_records=True, using='default')

#calls our api that returns list of objects

 c= record[0].persons.all() #dont be confused it accesses manytomany field in the object

 for f in c:

 email=f.email

# different type of assertions

 self.assertIsInstance(record[0], PersonModel)

 self.assertEquals(record[0].name_first, ';John;')

 self.assertEquals(record[0].name_last, ';Doe;')

 self.assertEquals(email, ';jdoe@testemail.com;')

 def test_get_match_initials(self):

 """Matches persons aganist the first name, last name or email provided

 using only initials of the name and full email when they are not found

 using the full name."""

 # Create a person

 PersonModelAutoFixture(PersonModel, data={

 'name_first': ';John;', 'name_last': ';Doe;',

 'email': ';jdoe@testemail.com;'},generate_fk=True).create(1)

 record = self.canon._get(name_first='Jeff',name_last='Doorstep',

 email='jdoe@testemail.com', match_records=True, using='default')

 c= record[0].persons.all()

 for f in c:

 email=f.email

 self.assertIsInstance(record[0], PersonModel)

 self.assertEquals(record[0].name_first, ';John;')

 self.assertEquals(record[0].name_last, ';Doe;')

 self.assertEquals(email, ';jdoe@testemail.com;')
Autofixture Part
# App

from application import models

# Autofixture

from autofixture import generators, register, AutoFixture

class CanonAutoFixture(AutoFixture):

def __init__(self, model, data={}, *args, **kwargs):

 self.data = data

 kwargs['generate_fk'] = True # this is our default because we have lot of dependency so we let this to handled by autofixtures

 kwargs['field_values'] =data # the field values are overridden with the values provided else autofixtures will set them with junk values

 super(CanonAutoFixture, self).__init__(

 model,*args, **kwargs)

 def post_process_instance(self, instance, commit):

 if self.vpd_field != False: #it is passed on by the fixture see below

 vpds_args = {

 self.vpd_id: getattr(instance, self.vpd_id) #it is passed on by the fixture see below 

 }

 # this method is very slow ...

 for i,v in self.data.iteritems():

 for a in self.vpd_model._meta.fields: #it is passed on by the fixture see below 

 if i == a.name:

 vpds_args[i] = v

 canon_model = AutoFixture(self.vpd_model, vpds_args, generate_fk=True).create(1,using=self._using)[0]<span style="font-weight: 400;j"> # if we have a more than one databases then we need this as i have a set of virtual private databases (VPD in short)so i use the using attribute to store at my prefered vpd.

 getattr(instance, self.vpd_field).add(canon_model)

class PersonModelAutoFixture(CanonAutoFixture):

 field_values = {

 'therapy': generators.StringGenerator(max_length=60),

 }

 #i have some virtual private databases so i have this use you can skip.

# here i have used some variables to pass the CanonAutoFixture

 vpd_model = models.Person

 vpd_field = 'persons'

 vpd_id = 'p_id'

# register with autofixture

register(models.PersonModel, PersonModelAutoFixture)

 

We just saw how we can start using Autofixtures for our unit tests, and how quickly we can create objects in our database without writing management commands or loading fixtures.

Drop me a comment if you have any queries. 

To learn more about

Contact Us

Leave a Reply

Your email address will not be published. Required fields are marked *

Tools & Practices

Tools and Technologies we use at Applied

Contact us now

Popular Posts