2013-10-02 9 views
8

Używam factory_boy do tworzenia urządzeń testowych. Mam dwie proste fabryki, wspierane przez modele SQLAlchemy (uproszczone poniżej).Unikanie duplikatów w fabrykach factory_boy

Chciałbym móc wielokrotnie wywoływać numer AddressFactory.create() i utworzyć go jako Country, jeśli jeszcze nie istnieje, w przeciwnym razie chcę, aby ponownie wykorzystał istniejący rekord.

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

Moje pytanie brzmi: w jaki sposób można skonfigurować tak, że te fabryki factory_boy nie stara się tworzyć nowego kraju za każdym razem tworzy adres?

+0

Czy przyjrzeć [factory.alchemy] (https://github.com/rbarrois/factory_boy/blob/master/factory /alchemy.py)? – javex

+0

Nie wiesz, do czego masz na myśli ten link; w tym konkretnym pliku nie ma nic, co wydaje się pomocne. Przyjrzałem się dokumentom dla factory_boy i fabryki SQLAlchemy w szczególności, ale nie widziałem nic o ponownym użyciu rekordów. Zasadniczo poszukuje funkcji typu "znajdź lub utwórz". –

+0

Po dalszych badaniach, krótka odpowiedź brzmi, że nie możesz tego zrobić. Istnieje wsparcie dla [get-or-create z modelami Django] (https://factoryboy.readthedocs.org/en/latest/orms.html#factory.django.DjangoModelFactory.FACTORY_DJANGO_GET_OR_CREATE), ale nie SQLAlchemy. Pozostawiam to pytanie otwarte, ponieważ mam nadzieję na dodanie wsparcia SQLAlchemy na ten jeden z tych dni, jeśli nikt mnie do tego nie pobije. –

Odpowiedz

4

W najnowszym fabrycznie chłopiec == 2.3.1 można dodać 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" 

Zakładając polu DW jest unikatowy identyfikator.

+0

Jak już wspomniałem w powyższym pytaniu i komentarzu powyżej, używam SQLAlchemy. Wiem, że to istnieje dla Django, ale to mi nie pomoże. Funkcjonalność, której szukam, nie istnieje w fabryce, a ja wciąż nie miałem czasu, aby ją dodać. –

2

Choć masz rację, że nie ma get_or_create funkcja dla fabryk SQLAlchemy opartych jeżeli obiekty, które chcesz użyć jako klucza obcego już istnieje, można wykonać iterację nich:

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

Tak prawdopodobnie można zhakować razem rozwiązanie w twojej fabryce, używając leniwego atrybutu, który najpierw sprawdza, czy obiekt istnieje w db, a jeśli tak, to używa tej metody do iterowania przez nie, ale jeśli obiekt nie istnieje, to wywołuje SubFactory, aby najpierw utworzyć obiekt.

+0

To zdecydowanie jest zbrodnicze rozwiązanie, o wiele lepiej, jeśli przesłałeś PR dodając opcję get_or_create dla SQLAlchemy ;-) –

0

Innym hackowskim rozwiązaniem jest nadpisanie metody fabryki create w taki sposób, że obiekt jest wyszukiwany przez zapytanie i buforowanie wyników.

Ten prosty przykład nie wykonuje filtrowanie na **kwargs choć:

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