I am trying to use Factory Boy in order to generate test data for my test suite. My data consists of JSON objects with a body
field that contains an escaped JSON String (example below). I also included example python dataclasses and Factory Boy factories for this example data.
Note: For this example, I am skipping the setup of fake data using Faker or the built-in fuzzers to simplify the question. In a more realistic use case, fields like eventtime
, deviceid
, enqueuedTime
would contain rondomized values (using a fixed seed for the randomness)
I am struggling to figure out how to generate the inner JSON object and stringify it using Factory Boy.
An example data point:
{
"body": "{\"eventdata\":{\"count\":\"1\",\"sourceid\":\"0\",\"updatetime\":\"1579797993879\",\"description\":\"Lorem ipsum dolor sit amet, consectetur adipiscing elit\"},\"eventtime\":\"2020-01-23T16:46:35.522Z\",\"eventversion\":\"1.0.0\",\"eventtype\":\"FooEventType\",\"deviceid\":\"000000123ABC\"}",
"partition": "30",
"enqueuedTime": "2020-01-23T16:46:35.594Z",
"event_type": "FooEventType",
"year": 2020,
"month": 1,
"day": 23}
My Python dataclasses and Factory Boy factories:
from dataclasses import dataclass
import factory
@dataclass
class Root:
body: str
partition: str
enqueued_time: str
event_type: str
year: int
month: int
day: int
@dataclass
class Eventdata:
count: str
sourceid: str
updatetime: str
description: str
@dataclass
class Body:
eventdata: Eventdata
eventtime: str
eventversion: str
eventtype: str
deviceid: str
class EventdataFactory(factory.Factory):
class Meta:
model = Eventdata
count = "1"
sourceid = "0"
updatetime = "1579797993879"
description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
class BodyFactory(factory.Factory):
class Meta:
model = Body
eventdata = factory.SubFactory(Eventdata)
eventtime = "2020-01-23T16:46:35.522Z"
eventversion = "1.0.0"
eventtype = "FooEventType" # Note: It is the same in Root
deviceid = "000000123ABC"
class RootFactory(factory.Factory):
class Meta:
model = Root
body = "Escaped JSON String" # Need help here
partition = "30"
enqueuedTime = "2020-01-23T16:46:35.594Z"
event_type = "FooEventType" # Note: It is the same in Body
year = 2020
month = 1
day = 23
How do I create the escaped JSON string build from 'BodyFactory' for the body
field in 'RootFactory'?
You can use Params
to declare the "structured" body, and a LazyAttribute
to convert it to JSON:
class RootFactory(factory.Factory):
class Meta:
model = Root
class Params:
body_raw = factory.SubFactory(BodyFactory)
partition = 30
enqueuedTime = "2020-01-23T16:46:35.594Z"
# Copy Body.event_type to Root.event_type
event_type = factory.SelfAttribute('.body_raw.event_type')
# Convert `body_raw` to JSON
body = factory.LazyAttribute(lambda o: json.dumps(o.body_raw))
In this model, the raw "Body" object is built as a SubFactory
(in class Params
), but only available during the factory evaluation: body_raw
won't be passed to the dataclass constructor.
The body
field is then built by encoding the contents to JSON - or any other custom method for converting a Body
object to JSON.
NB: I've also used a factory.SelfAttribute
to copy the event_type
from BodyFactory
to RootFactory
.