Expressive struct generation for your Go tests.
go get github.com/ckbaum/go-fabricate
Let's define a User
struct:
type User struct {
FirstName string
LastName string
Email *string
Verified bool
Friends []*User
}
After defining a Fabricator
, fake Users
can easily be generated with random, non-zero data.
userFabricator := fabricate.Define(User{})
user := userFabricator.Fabricate().(*User)
// User{
// FirstName: "Leqrewn",
// LastName: "Rnzenfjq",
// Email: &"Hnaeqwk",
// Verified: true,
// Friends: {&User{...}, &User{...},},
// }
With a barebones Fabricator
like this one:
- All fields with composite data types will be set to a random value
- Pointers, slices and maps with composite element types will be populated
- Fields of the same type as the fabricated struct will also be generated using the fabricator (to a configurable depth.)
After adding some custom field definitions, our userFabricator
can generate more realistic users:
userFabricator := fabricate.Define(
User{},
).Field("Verified", func(_ fabricate.Session) interface{} {
// have all our test users be verified
return true
}).Field("FirstName", func(_ fabricate.Session) interface{} {
// realistic names with help from a fake data package
return gofakeit.FirstName()
})
user := userFabricator.Fabricate().(*User)
// User{
// FirstName: "James",
// LastName: "Poadarp",
// Email: &"Ejasdklf",
// Verified: true,
// Friends: {&User{...}, &User{...},},
// }
Field definitions can reference the in-progress struct's other fields through the Session
parameter. Here, Email
references the in-progress struct (through Session
) to incorporate the user's name.
userFabricator := fabricate.Define(
User{},
).Fields([]string{"FirstName", "LastName"}, func(_ fabricate.Session) interface{} {
// realistic names with help from a fake data package
// this time, FirstName and LastName share a generator
return gofakeit.FirstName()
}).Field("Email", func(session fabricate.Session) interface{} {
// an email based on this user's name
email := fmt.Sprintf(
"%s.%[email protected]",
session.Struct.(*User).FirstName,
session.Struct.(*User).LastName,
)
return &email
})
user := userFabricator.Fabricate().(*User)
// User{
// FirstName: "James",
// LastName: "Joyce",
// Email: &"[email protected]",
// Verified: true,
// Friends: {&User{...}, &User{...},},
// }
Variations of Fabricators can be defined with Traits, and applied at fabrication time.
userFabricator.Trait(
"no email",
).Field("Email", func(_ fabricate.Session) interface{} {
return nil
}).Field("Verified", func(_ fabricate.Session) interface{} {
return false
})
user := userFabricator.Fabricate("no email").(*User)
// User{
// FirstName: "James",
// LastName: "Joyce",
// Email: nil,
// Verified: false,
// Friends: {&User{...}, &User{...},},
// }
If you've defined multiple traits, they can be combined during fabrication:
userFabricator.Trait(
"short name",
).Field("FirstName", func(_ fabricate.Session) interface{} {
return "Em"
})
user := userFabricator.Fabricate("no email", "short name").(*User)
// User{
// FirstName: "Em",
// LastName: "Joyce",
// Email: nil,
// Verified: false,
// Friends: {&User{...}, &User{...},},
// }
By defining a Registry
that tracks multiple fabricators, nested Structs will automatically be generated using the appropriate Fabricator
.
Consider two Structs , Author
and Book
type Author struct {
Name string
Country string
Books []*Book
}
type Book struct {
Title string
Language string
}
This time, we'll define a Registry
and define our two fabricators into the Registry.
fabricatorRegistry := fabricate.NewRegistry()
authorFabricator := fabricatorRegistry.Define(
Author{},
).Register(fabricatorRegistry)
bookFabricator := fabricatorRegistry.Define(
Book{},
).Field("Language", func(_ fabricate.Session) interface{} {
return []string{"English", "French"}[rand.Intn(2)]
}).Register(fabricatorRegistry)
Because these Fabricators
are defined within the same Registry
, the Books
field in Author
will be generated using bookFabricator
by default.
authorFabricator.Fabricate().(Author)
// Author{
// Name: "Ejasdlf",
// Country: "Pasfaf",
// Books: []*Book{
// &Book{
// Title: "Peafee",
// Language: "English"
// },
// &Book{
// Title: "Peafee",
// Language: "French"
// },
// &Book{
// Title: "Peafee",
// Language: "French"
// },
// }
The MIT License (MIT) - see LICENSE.md for more details