2013-10-02 8 views
8

Ich benutze factory_boy um Test Fixtures zu erstellen. Ich habe zwei einfache Fabriken, unterstützt von SQLAlchemy-Modellen (unten vereinfacht).Vermeidung von Duplikaten mit factory_boy factories

Ich möchte AddressFactory.create() mehrere Male anrufen, und habe es eine Country erstellen, wenn es nicht bereits vorhanden ist, andernfalls möchte ich es den vorhandenen Datensatz verwenden.

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

Meine Frage ist: Wie kann ich diese Fabriken so einrichten, dass factory_boy versucht nicht, ein neues Land jedes Mal, es schafft eine Adresse zu erstellen?

+0

Haben Sie bei [factory.alchemy] einen Blick (https://github.com/rbarrois/factory_boy/blob/master/factory /alchemy.py)? – javex

+0

Nicht sicher, was Sie in diesem Link beziehen; In dieser speziellen Datei ist nichts hilfreich. Ich habe mir die Dokumente für factory_boy und die SQLAlchemy Factory genauer angeschaut, aber ich habe nichts über die Wiederverwendung von Datensätzen gesehen. Suchen Sie im Grunde nach einer Funktionalität vom Typ "Suchen oder Erstellen". –

+0

Nach mehr Forschung dazu ist die kurze Antwort, dass Sie es nicht tun können. Es gibt Unterstützung für [get-or-create mit Django-Modellen] (https://factoryboy.readthedocs.org/en/latest/orms.html#factory.django.DjangoModelFactory.FACTORY_DJANGO_GET_OR_CREATE), aber nicht SQLAlchemy. Ich lasse diese Frage offen, weil ich hoffe, SQLAlchemy Unterstützung für diesen einen von diesen Tagen hinzuzufügen, wenn niemand mich dazu schlägt. –

Antwort

4

In der neuesten Werk-boy == 2.3.1 können Sie hinzufügen FACTORY_DJANGO_GET_OR_CREATE

class CountryFactory(factory.django.DjangoModelFactory): 
    FACTORY_FOR = 'appname.Country' 
    FACTORY_DJANGO_GET_OR_CREATE = ('cc',) 

    cc = "US" 
    name = "United States" 

cc Feld Unter der Annahme, die eindeutige Kennung ist.

+0

Wie ich in meinem Frage- und Folgekommentar oben erwähnte, verwende ich SQLAlchemy. Ich weiß, dass das für Django existiert, aber das hilft mir nicht. Die Funktionalität, nach der ich suche, existiert nicht in Fabrikjungen, und ich hatte immer noch nicht die Zeit, sie selbst hinzuzufügen. –

2

Während du hast Recht, dass es keine get_or_create Funktion für SQLAlchemy-basierte Fabriken, wenn die Objekte, die Sie als Fremdschlüssel bereits verwenden möchten vorhanden sind, können Sie durch sie durchlaufen:

http://factoryboy.readthedocs.org/en/latest/recipes.html#choosing-from-a-populated-table

So denkbar wäre, dass Sie eine Lösung in Ihrer Fabrik zusammenhacken könnten, indem Sie ein Lazy-Attribut verwenden, das zuerst prüft, ob das Objekt in der DB existiert, und wenn ja, wird diese Methode verwendet, um sie zu durchlaufen, aber wenn das Objekt nicht existiert, ruft es ein SubFactory um das Objekt zuerst zu erstellen.

+0

Dies ist definitiv eine Hacky-Lösung, viel besser, wenn Sie eine PR eingereicht haben, die die Fähigkeit get_or_create für SQLAlchemy hinzufügt ;-) –

0

Eine andere hacky Lösung ist die create Methode der Fabrik in einer Weise zu überschreiben, dass das Objekt durch eine Abfrage und Zwischenspeichern der Ergebnisse gesucht wird.

Dieses einfache Beispiel führt keine Filterung auf der **kwargs aber:

class StaticFactory(SQLAlchemyModelFactory):       

    counter = 0              
    cache = []              
    model = None              

    @classmethod              
    def create(cls, **kwargs):          
     if not cls.cache:           
      cls.cache = your_session.query(cls.model).all()  
     instance = cls.cache[cls.counter]       
     cls.counter = (cls.counter + 1) % len(cls.cache)    
     return instance            
Verwandte Themen