Search code examples
pythondjangofactory-boy

Django FactoryBoy - random choice not working with LazyFunction


I'm building a number of tests for our django application and I'm using FactoryBoy

The Profile model has a gender field which is defined as follows:

class Profile(models.Model):

  GENDER_CHOICES = (
    (u'm', _(u'Male')),
    (u'f', _(u'Female')),
  ) 

 gender = models.CharField(
   max_length=2, choices=GENDER_CHOICES, verbose_name=_("Gender"),
   null=True, blank=True
 ) 

I wanted to randomize the value of this field in factory boy with the following line of code:

class ProfileFactory(factory.Factory):
   (...)
   gender = factory.LazyFunction(random.choice(['f', 'm']))

However, this throws a TypeError: 'str' object is not callable error Using an old blogpost I then tried the following solution, which worked:

gender = factory.LazyAttribute(lambda x: random.choice(['f', 'm']))

This solved the problem, but its unclear to me why it did.

The documentation for factory.LazyFunction states that:

The LazyFunction is the simplest case where the value of an attribute
 does not depend on the object being built.

It takes as argument a method to call (function, lambda…); that method 
should not take any argument, though keyword arguments are safe but 
unused, and return a value.

It was my understanding that random.choice(['f', 'm']) constituted a method call and thus should work as I expected it to.

But as it did not my understanding of LazyFunction is clearly flawed and I was hoping somebody could explain what I am doing wrong here


Solution

  • LazyFunction requires a callable: something that it can call.

    random.choice(['f', 'm']) returns a string; to make it a callable, the solution is LazyFunction(lambda: random.choice(['f', 'm'])).

    However, the best solution to your issue is to use factory.fuzzy.FuzzyChoice, designed specifically for your usecase:

    gender = factory.fuzzy.FuzzyChoice(['f', 'm'])

    This will perform the random calls on its own, and supports proper seeding/randomness management — see https://factoryboy.readthedocs.io/en/latest/reference.html#randomness-management for details.