如何使用factory boy测试SQLalchemy关联对象模型?

如何使用factory boy测试SQLalchemy关联对象模型?,sqlalchemy,flask-sqlalchemy,pytest,factory-boy,Sqlalchemy,Flask Sqlalchemy,Pytest,Factory Boy,我将SQLalchemy关联对象模式()用于三个模型类 基本关系在左侧,一个用户可以属于多个组织。我正在关联对象类中存储额外的用户组织相关数据。然后,关联对象类将多对一映射到组织 从SQLAlchemy的角度来看,这种关系运作良好。用factory boy测试这个问题被证明是困难的,并且总是导致错误递归错误:超过最大递归深度 以下是关联对象关系的三种模型,其中用户是父对象,子对象是组织: class MemberOrgsAssoc(Model): """The left side

我将SQLalchemy关联对象模式()用于三个模型类

基本关系在左侧,一个用户可以属于多个组织。我正在关联对象类中存储额外的用户组织相关数据。然后,关联对象类将多对一映射到组织

从SQLAlchemy的角度来看,这种关系运作良好。用factory boy测试这个问题被证明是困难的,并且总是导致错误
递归错误:超过最大递归深度

以下是关联对象关系的三种模型,其中用户是父对象,子对象是组织:

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")
因此,以上所有SQLAlchemy模型类和关系似乎都能按预期工作

下面是我正在尝试的三个工厂男孩课程

MemberOrgs关联对象工厂:

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')])
最后,需要为测试创建一个用户,因此下面是一个pytestfixture来创建用户。这是由于“RecursionError:超过最大递归深度”而导致测试失败的地方

错误消息:

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

或多或少地解决了这个问题,尽管总体上有点脆弱。必须仔细遵循要求的模式:

对pytest夹具的以下更改解决了递归错误问题并使其正常工作:

@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
""" 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)
"""   
@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