How do you use factory_boy to model a MongoEngine EmbeddedDocument?
Asked Answered
B

2

8

I'm trying to use factory_boy to help generate some MongoEngine documents for my tests. I'm having trouble defining EmbeddedDocumentField objects.

Here's my MongoEngine Document:

class Comment(EmbeddedDocument):
    content = StringField()
    name = StringField(max_length=120)

class Post(Document):
    title = StringField(required=True)
    tags = ListField(StringField(), required=True)
    comments = ListField(EmbeddedDocumentField(Comment))

Here's my partially completed factory_boy Factory:

class CommentFactory(factory.Factory):
    FACTORY_FOR = Comment
    content = "Platinum coins worth a trillion dollars are great"
    name = "John Doe"

class BlogFactory(factory.Factory):
    FACTORY_FOR = Blog
    title = "On Using MongoEngine with factory_boy"
    tags = ['python', 'mongoengine', 'factory-boy', 'django']
    comments = [factory.SubFactory(CommentFactory)] # this doesn't work

Any ideas how to specify the comments field? The problem is that factory-boy attempts to create the Comment EmbeddedDocument.

Bohi answered 15/1, 2013 at 20:22 Comment(0)
B
5

I'm not sure if this is what you want but I just started looking at this problem and this seems to work:

from mongoengine import EmbeddedDocument, Document, StringField, ListField, EmbeddedDocumentField
import factory

class Comment(EmbeddedDocument):
    content = StringField()
    name = StringField(max_length=120)

class Post(Document):
    title = StringField(required=True)
    tags = ListField(StringField(), required=True)
    comments = ListField(EmbeddedDocumentField(Comment))


class CommentFactory(factory.Factory):
    FACTORY_FOR = Comment
    content = "Platinum coins worth a trillion dollars are great"
    name = "John Doe"

class PostFactory(factory.Factory):
    FACTORY_FOR = Post
    title = "On Using MongoEngine with factory_boy"
    tags = ['python', 'mongoengine', 'factory-boy', 'django']
    comments = factory.LazyAttribute(lambda a: [CommentFactory()])

>>> b = PostFactory()
>>> b.comments[0].content
'Platinum coins worth a trillion dollars are great'

I wouldn't be surprised if I'm missing something though.

Bryan answered 13/8, 2013 at 7:1 Comment(1)
You need to include the EmbeddedDocumentFactory as the first guy has included to create the factory for the embedded document factory when we initialize the main factory.Occident
B
2

The way that I'm doing it right now is to prevent the Factories based on EmbeddedDocuments from building. So, I've setup up an EmbeddedDocumentFactory, like so:

class EmbeddedDocumentFactory(factory.Factory):

    ABSTRACT_FACTORY = True

    @classmethod
    def _prepare(cls, create, **kwargs):                                        
        return super(EmbeddedDocumentFactory, cls)._prepare(False, **kwargs)

Then I inherit from that to create factories for EmbeddedDocuments:

class CommentFactory(EmbeddedDocumentFactory):

    FACTORY_FOR = Comment

    content = "Platinum coins worth a trillion dollars are great"
    name = "John Doe"

This may not be the best solution, so I'll wait on someone else to respond before accepting this as the answer.

Bohi answered 16/1, 2013 at 3:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.