首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何正确地将FactoryBoy子工厂与子对象关联

如何正确地将FactoryBoy子工厂与子对象关联
EN

Stack Overflow用户
提问于 2018-12-04 20:16:57
回答 1查看 456关注 0票数 0

当我使用常规的数据库对象运行它们时,我有一些测试是有效的,但是由于我使用的是FactoryBoy工厂,这些测试已经失效。我想我理解他们为什么会崩溃,但我很难找到正确的方法来解决这个问题。

这里是我的工厂:

代码语言:javascript
复制
@register
class UserFactory(BaseFactory):
    """User factory."""

    username = Sequence(lambda n: 'user{0}'.format(n))
    email = Sequence(lambda n: 'user{0}@example.com'.format(n))
    password = PostGenerationMethodCall('set_password', 'example')
    active = True

    class Meta:
        """Factory configuration."""

        model = User

@register
class ExperimentFactory(BaseFactory):
    """Experiment Factory."""

    date = fake.date_this_decade(before_today=True, after_today=False)
    scanner = Iterator(['GE', 'Sie', 'Phi'])

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

    user = factory.SubFactory(UserFactory)

根据this answer和其他示例,FactoryBoy应该在幕后处理外键分配。

但是,当我试图在我的夹具中初始化我的ExperimentFactory对象时,我遇到了一个问题。

代码语言:javascript
复制
@pytest.fixture(scope='function')
@pytest.mark.usefixtures('db')
def mocked_scan_service(db, mocker, request):
    user = UserFactory(password='myprecious')
    db.session.add(user)
    num_exp, num_scans, exp_id, scan_id, exp_uri, scan_uri = request.param

    for i in range(num_exp):
        experiment = ExperimentFactory(user_id = user.id)
        db.session.add(experiment)

    db.session.commit()

    ss = ScanService(user.id, experiment.id)
    for i in range(num_scans):
        ss._add_scan_to_database()

    ss.xc.upload_scan = mocker.MagicMock()
    ss.xc.upload_scan.return_value = ('/data/archive/subjects/000001', exp_uri, scan_uri)
    mocker.spy(ss, '_generate_xnat_identifiers')
    ss.param = request.param
    return ss

如果我没有向ExperimentFactory传递用户id,则会得到以下错误:

代码语言:javascript
复制
TypeError: __init__() missing 1 required positional argument: 'user_id'

下面是模型;对于我来说,工厂需要一个参数user_id来初始化,这是有意义的:

代码语言:javascript
复制
class Experiment(SurrogatePK, Model):
    """A user's experiment, during which they are scanned."""

    __tablename__ = 'experiment'
    date = Column(db.Date(), nullable=False)
    scanner = Column(db.String(80), nullable=True)
    num_scans = Column(db.Integer(), nullable=True, default=0)
    xnat_experiment_id = Column(db.String(80), nullable=True)
    xnat_uri = Column(db.String(80), nullable=True)
    user_id = reference_col('user', nullable=False)
    scans = relationship('Scan', backref='experiment')

    def __init__(self, date, scanner, user_id, **kwargs):
        """Create instance."""
        db.Model.__init__(self, date=date, scanner=scanner, user_id=user_id, **kwargs)

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<Experiment({date})>'.format(date=self.date)

但是,如果按照所写的方式,我显式地创建了一个用户,然后传递用户id,那么看起来ExperimentFactory最终会用它生成的SubFactory覆盖外键。因此,稍后当我初始化一个名为ScanService的对象(必须使用user_id和和experiment_id进行初始化)时,我的测试失败有两个原因之一。要么我用我显式创建的用户的user_id初始化它,我的测试失败是因为他们找不到experiment_id所属的实验的同级实验,要么我用experiment.user.id初始化它,我的测试失败是因为他们期望数据库中有一个用户,实际上有两个。后一个问题可以很容易地通过重写我的测试来解决,但这似乎很简陋和不清楚。当实验模型需要一个user_id进行初始化时,我该如何初始化user_id?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-12-05 01:01:10

如果有人有更好的解决方案,可以随意评论,但我意识到:我为user_id传递的内容并不重要;我只需要传递一些东西,这样模型初始化就不会失败。同时传入user=user创造了我想要的情况:所有的实验都属于同一个用户。现在我所有的测试都通过了。以下是修改后的夹具代码;其他所有内容都保持不变:

代码语言:javascript
复制
@pytest.fixture(scope='function')
@pytest.mark.usefixtures('db')
def mocked_scan_service(db, mocker, request):
    num_exp, num_scans, exp_id, scan_id, exp_uri, scan_uri = request.param

    user = UserFactory(password='myprecious')

    for i in range(num_exp):
        experiment = ExperimentFactory(user_id=user.id, user=user)
        db.session.add(experiment)

    db.session.commit()

    ss = ScanService(experiment.user.id, experiment.id)
    for i in range(num_scans):
        ss._add_scan_to_database()

    ss.xc.upload_scan = mocker.MagicMock()
    ss.xc.upload_scan.return_value = ('/data/archive/subjects/000001', exp_uri, scan_uri)
    mocker.spy(ss, '_generate_xnat_identifiers')
    ss.param = request.param
    return ss
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53620764

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档