Tom Brown
Tom Brown

Reputation: 316

factoryboy override attribute of lazy_attribute

I have some nested google.proto.message objects and am trying to override an attribute deep inside the parent model when making test data with factoryboy. Some of the children messages are created with a lazy_attribute which contains logic to populate them using other objects. I've reproduced the issue I'm having in factoryboy with a much simpler example using attrs models.

class BookFactory(factory.Factory):
  class Meta:
    model = models.Book

  class Params:
    num_pages = 10

  @factory.lazy_attribute
  def pages(self):
    return PageFactory.build_batch(self.num_pages)


book = BookFactory.build(
  num_pages=3,
  pages__0__content='mypage0',
)

# This fails. How do I override pages[0].content with a BookFactory attribute?
assert book.pages[0].content == 'mypage0'

I have an running example of the failure at https://repl.it/@TomGoBravo/lazyattributesubfactory

Thank you for any suggestions you have!

Upvotes: 0

Views: 926

Answers (2)

smilerz
smilerz

Reputation: 41

You can use a post_generation method to control the number of items created as well as the attributes of the underlying model.

class BookFactory(factory.Factory):
  class Meta:
    model = models.Book

@factory.post_generation
def pages(self, create, extracted, **kwargs):
    if not create:
        return
    num_pages = kwargs.get('num_pages', 0)
    if num_pages > 0:
        book.pages = <---code goes here--->

book = BookFactory.build(
  pages__num_pages=3,
  pages__0__content='mypage0',
)

Upvotes: 0

Xelnor
Xelnor

Reputation: 3589

The best way would be with a SubFactory wrapped in factory.List, but you'll lose the ability to adjust the length of said list:

class BookFactory(factory.Factory):
    class Meta:
        model = models.Book

    pages = factory.List([
        factory.SubFactory(PageFactory),
        factory.SubFactory(PageFactory),
        factory.SubFactory(PageFactory),
    ])

Otherwise, you'd have to implement (and contribute !) some form of SubFactoryList, similar to the existing RelatedFactoryList.

Upvotes: 1

Related Questions