У меня есть несколько тестов, которые работали, когда я запускал их с обычными объектами базы данных, но теперь они не работают, когда я использую фабрики 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)
Согласно этот ответ и другие примеры. Предполагается, что 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 идентификатор пользователя, я получаю эту ошибку:
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)
Но если, как написано, я явно создаю пользователя и затем передаю идентификатор пользователя, похоже, что ExperimentFactory в конечном итоге перезаписываетвнешний ключ с подфабрикой, которую он сгенерировал.Итак, позже, когда я инициализирую объект с именем ScanService
, который должен быть инициализирован с помощью user_id и и analysis_id, мои тесты не пройдены по одной из двух причин.Либо я инициализирую его с помощью user_id моего явно созданного пользователя, и мои тесты не пройдены, потому что они не находят никаких родственных экспериментов в эксперименте, которому принадлежит Experin_id, или я инициализирую его с экспериментом.user.id, и мои тесты не выполняются, потому чтоони ожидают одного пользователя в базе данных, а на самом деле их два.Эту последнюю проблему довольно легко обойти, переписав мои тесты, но это кажется неопрятным и неясным.Как я должен инициализировать ExperimentFactory, когда для экспериментальной модели требуется user_id для инициализации?