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.