当我使用常规数据库对象运行它们时,我有一些测试正在运行,但是由于我正在使用FactoryBoy工厂而被破坏了。我想我理解他们为什么会损坏,但正在努力进行正确的设置。
这是我的工厂:
@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对象时,我遇到了问题。
@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,则会出现此错误:
TypeError: __init__() missing 1 required positional argument: 'user_id'
这是模特儿;对我来说,工厂需要一个参数user_id进行初始化是很有意义的:
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和and Experiment_id进行初始化)时,由于两个原因之一,测试失败。我要么用我显式创建的用户的user_id对其进行初始化,而我的测试失败,因为它们没有找到实验所属的实验的同级实验,或者我使用了Experiment.user.id对其进行了初始化,而我的测试却因为失败他们期望数据库中有一个用户,实际上有两个。通过重写我的测试,可以很容易地解决后一个问题,但这似乎很不稳定而且不清楚。当实验模型需要user_id进行初始化时,我应该如何初始化ExperimentFactory?
答案 0 :(得分:0)
如果有人有更好的解决方案,请随时发表评论,但这就是我意识到的:我为user_id传递的内容并不重要;我只需要传递一些信息,以确保模型初始化不会失败。同时传递user=user
会造成我想要的情况:所有实验都属于同一用户。现在我所有的测试都通过了。这是修改后的灯具代码;其他所有内容都保持不变:
@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