I have a class, for which I would like to write a factory using FactoryBoy. However, this class doesn't produce its instances using the __init__ method, but rather a number of factory methods:
class MyClass:
def __init__():
self.field = None
self.is_valid = False
@staticmethod
def from_str(arg):
inst = MyClass()
inst.field = arg
inst.is_valid = True
return inst
Is there a way to write a FactoryBoy factory such that it uses this static factory method instead of passing the fields to MyClass initialiser?
The way to do this is to override the _build(...) or _create(...) classmethod on your Factory subclass.
Assuming the arg in your class is described by the text parameter of your factory:
class MyFactory(factory.Factory):
class Meta:
model = MyClass
@classmethod
def _create(cls, model_class, *args, text, **kwargs):
return model_class.from_string(text)
text = factory.Sequence("some-input:{}".format)
With that code, calling MyFactory() would call MyClass.from_string("some-input:0"); and calling MyFactory(text="some-data") will return the value from MyClass.from_string("some-data").
If you have lots of classes using that same mechanism, you may even add a custom abstract factory to share that def _create declaration:
class FromStringFactory(factory.Factory):
class Meta:
abstract = True
@classmethod
def _create(cls, model_class, *args, text, **kwargs):
return model_class.from_string(text, **kwargs)
class SomeClassFactory(FromStringFactory):
class Meta:
model = SomeClass
text = factory.Faker("country")