I am struggling finding a way to have a class Factory (I use factory_boy
version 2.11.1 with Python 3) using an alternate constructor defined as a @classmethod
.
So let's say we have a class for building a 2D-point object with a default constructor and 2 additional ones:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def fromlist(cls, coords): # alternate constructor from list
return cls(coords[0], coords[1])
@classmethod
def duplicate(cls, obj): # alternate constructor from another Point
return cls(obj.x, obj.y)
I create a basic Point factory:
import factory
class PointFactory(factory.Factory):
class Meta:
model = Point
inline_args = ('x', 'y')
x = 1.
y = 2.
By default, it seems to call the constructor __init__
of the class which seems very logical. I could not find a way to pass inline_args
as being coords
for using the alternate constructor fromlist
. Is there a way to do so?
This is my first experience working and building factories in general so I may also be looking up at the wrong keywords on the web...
The point of factory_boy
is to make it easy to produce test instances. You'd just call PointFactory()
and you are done, you have test instances for the rest of your code. This usecase doesn't need to use any of the alternative constructors, ever. The factory would just use the main constructor.
If you are thinking that factory_boy factories must be defined to test your extra constructors, then you have misunderstood their use. Use factory_boy factories to create test data for other code to be tested. You'd not use them to test the Point
class (other than to generate test data to pass to one of your constructors).
Note that inline_args
is only needed if your constructor doesn't accept keyword arguments at all. Your Point()
class has no such restriction; x
and y
can be used both as positional and as keyword arguments. You can safely drop inline_args
from your definition, the factory will work regardless.
If you must use one of the other constructors (because you can't create test data with the main constructor), just pass the specific constructor method in as the model:
class PointListFactory(factory.Factory):
class Meta:
model = Point.fromlist
coords = (1., 2.)