2017-07-18 2 views
4

Ich verwende das SQLalchemy association-object Muster (http://docs.sqlalchemy.org/en/rel_1_1/orm/basic_relationships.html#association-object) für drei Modellklassen.Wie wird Factory Boy zum Testen von SQLalchemy-Assoziationsobjektmodellen verwendet?

Grundlegende Beziehung ist auf der linken Seite ein Benutzer kann zu mehreren Organisationen gehören. Ich speichere zusätzliche benutzerorganisationsrelevante Daten in der Assoziationsobjektklasse. Dann ordnet die Assoziationsobjektklasse der Organisation eine Viele-zu-Eins-Beziehung zu.

Von SQLAlchemy Punkt funktioniert die Beziehung gut. Das Problem ist, dies mit Fabrikjungen zu testen, hat sich als schwierig erwiesen und führt immer zu einem Fehler .

Im Folgenden sind die drei Modelle für die Objekt-Beziehung Assoziation, wo Benutzer Elternteil und das Kind ist Organisation:

class MemberOrgsAssoc(Model): 
     """The left side of the relationship maps a User as a one-to-many to 
     Organizations. User-Organization relevant data is stored in 
     this association-object table. Then, there is a one-to-many from 
     this association-object table to the Organization table. """ 

     __tablename__ = 'member_orgs' 

     member_id = Column(db.Integer, db.ForeignKey("users.id"), primary_key=True) 
     org_id = Column(db.Integer, db.ForeignKey("organizations.id"), primary_key=True) 
     manager_id = Column(db.Integer, db.ForeignKey("users.id")) 
     org_title = Column(db.Unicode(50)) 
     organization = relationship("Organization", back_populates="members") 
     member = relationship("User", back_populates="organizations", 
           foreign_keys=[member_id]) 
     manager = relationship("User", back_populates="subordinates", 
           foreign_keys=[manager_id]) 

class User(SurrogatePK, Model): 
    """A user of the app.""" 
    __tablename__ = 'users' 

    username = Column(db.Unicode(80), unique=True, nullable=False) 
    organizations = relationship("MemberOrgsAssoc", back_populates="member", 
           primaryjoin = "member_orgs.c.member_id == User.id", 
           lazy="dynamic") 
    subordinates = relationship("MemberOrgsAssoc", back_populates="manager", 
           primaryjoin = "member_orgs.c.manager_id == User.id", 
           lazy="dynamic") 

class Organization(SurrogatePK, Model): 
    """An organization that Users may belong to.""" 
    __tablename__ = 'organizations' 
    name = Column(db.Unicode(128), nullable=False) 
    members = relationship("MemberOrgsAssoc", back_populates="organization") 

So sind alle oben SQLAlchemy Modellklassen und Beziehungen scheinen nun wie vorgesehen zu arbeiten.

Im Folgenden sind die drei Fabrik-Jungen-Klassen, die ich versuche, Arbeit zu machen.

MemberOrgs Verein-Objekt Fabrik:

class MemberOrgsAssocFactory(BaseFactory): 
    """Association-object table Factory""" 

    class Meta: 
     """Factory config""" 
     model = MemberOrgsAssoc 

    member_id = factory.SubFactory('tests.factories.UserFactory') 
    org_id = factory.SubFactory('tests.factories.OrganizationFactory') 
    manager_id = factory.SubFactory('tests.factories.UserFactory') 
    org_title = Sequence(lambda n: 'CEO{0}'.format(n)) 
    organization = factory.SubFactory('tests.factories.OrganizationFactory') 
    member = factory.SubFactory('tests.factories.UserFactory') 
    manager = factory.SubFactory('tests.factories.UserFactory') 

class UserFactory(BaseFactory): 
    """User factory.""" 

    class Meta: 
     """Factory configuration.""" 
     model = User 

    username = Sequence(lambda n: 'user{0}'.format(n)) 
    organizations = factory.List(
     [factory.SubFactory('tests.factories.MemberOrgsAssocFactory')]) 
    subordinates = factory.List(
     [factory.SubFactory('tests.factories.MemberOrgsAssocFactory')]) 

class OrganizationFactory(BaseFactory): 
    """Company factory""" 

    class Meta: 
     """Factory config""" 
     model = Organization 

    id = Sequence(lambda n: '{0}'.format(n)) 
    name = Sequence(lambda n: 'company{0}'.format(n)) 
    members = factory.List(
     [factory.SubFactory('tests.factories.MemberOrgsAssocFactory')]) 

Schließlich müssen einen Benutzer für die Tests machen und so ist eine pytest Befestigung eines Benutzers zu machen. Dies ist, wo die Tests fehlschlagen aufgrund `RecursionError: maximale Rekursionstiefe überschritten“

@pytest.fixture(scope='function') 
def user(db): 
    """An user for the unit tests. 
    setup reference: https://github.com/FactoryBoy/factory_boy/issues/101 
    # how to handle self referential foreign key relation in factory boy 
    # https://github.com/FactoryBoy/factory_boy/issues/173 
    """ 
    user = UserFactory(
     organizations__0=None, 
     subordinates__0=None, 
    ) 

    a = MemberOrgsAssocFactory(
     is_org_admin=True, 
     is_default_org=True, 
     is_active=True, 
    ) 

    a.organization=OrganizationFactory() 
    user.organizations.append(a) 

    db.session.commit() 
    return user 

Fehlermeldung:.

E RecursionError: maximum recursion depth exceeded 
!!! Recursion detected (same locals & position) 

Antwort

1

Mehr oder weniger das Problem gelöst, wenn auch ein wenig zerbrechlich Gesamt Muss erforderlich Muster folgen. sorgfältig as laid out in the sqlalchemy docs:

""" EXAMPLE USE: 
# create User object, append an Organization object via association 
p = User() 
a = MemberOrgsAssoc(extra_data="some data") 
a.organization = Organization() 
p.organizations.append(a) 

# iterate through Organization objects via association, including association attributes: 
for assoc in p.organizations: 
    print(assoc.extra_data) 
    print(assoc.child) 
""" 

Unten Änderungen an der pytest Halterung löste das RecursionError Problem und habe es funktioniert:

@pytest.fixture(scope='function') 
def user(db): 
    """An user for the tests.""" 

    user = UserFactory(
     organizations='', 
     subordinates='' 
    ) 

    a = MemberOrgsAssocFactory(
     member_id=None, 
     org_id=None, 
     manager_id=None, 
     is_org_admin=True, 
     is_default_org=True, 
     is_active=True, 
     organization=None, 
     member=None, 
     manager=None 
    ) 
    a.organization = OrganizationFactory(members=[]) 
    user.organizations.append(a) 
    db.session.commit() 

    # debugging 
    # thisuser = User.get_by_id(user.id) 
    # for assoc in thisuser.organizations: 
    # if assoc.is_default_org: 
    #  print('The default organization of thisuser is -> {}'.format(assoc.organization.name)) 

    return user 
Verwandte Themen