I'm using factory_boy to create test fixtures. I've got two simple factories, backed by SQLAlchemy models (simplified below).
I'd like to be able to call AddressFactory.create()
multiple times, and have it create a Country
if it doesn't already exist, otherwise I want it to re-use the existing record.
class CountryFactory(factory.Factory):
FACTORY_FOR = Country
cc = "US"
name = "United States"
class AddressFactory(factory.Factory):
FACTORY_FOR = Address
name = "Joe User"
city = "Seven Mile Beach"
country = factory.SubFactory(CountryFactory, cc="KY", name="Cayman Islands")
My question is: how can I set up these factories so that factory_boy doesn't try to create a new Country every time it creates an Address?
Since version 3.0.0, SQLAlchemy factories support the sqlalchemy_get_or_create
option. As the documentation says, "Fields whose name are passed in this list will be used to perform a Model.query.one_or_none() or the usual Session.add()".
Using the example from the docs:
class UserFactory(factory.alchemy.SQLAlchemyModelFactory):
class Meta:
model = User
sqlalchemy_session = session
sqlalchemy_get_or_create = ('username',)
username = 'john'
>>> User.query.all()
[]
>>> UserFactory() # Creates a new user
<User: john>
>>> User.query.all()
[<User: john>]
>>> UserFactory() # Fetches the existing user
<User: john>
>>> User.query.all() # No new user!
[<User: john>]
>>> UserFactory(username='jack') # Creates another user
<User: jack>
>>> User.query.all()
[<User: john>, <User: jack>]
Take into consideration that when sqlalchemy_get_or_create
is used, any new values passed to the factory are NOT used to update an existing model.