https://github.com/bluele/factory-go
A library for setting up Golang objects inspired by factory_bot.
https://github.com/bluele/factory-go
factory-boy factory-girl fixtures-replacement go golang
Last synced: 2 months ago
JSON representation
A library for setting up Golang objects inspired by factory_bot.
- Host: GitHub
- URL: https://github.com/bluele/factory-go
- Owner: bluele
- License: mit
- Created: 2015-10-04T12:56:57.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2023-04-05T10:47:32.000Z (about 2 years ago)
- Last Synced: 2024-10-13T21:05:17.124Z (8 months ago)
- Topics: factory-boy, factory-girl, fixtures-replacement, go, golang
- Language: Go
- Homepage:
- Size: 37.1 KB
- Stars: 373
- Watchers: 10
- Forks: 21
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# factory-go

[](https://pkg.go.dev/github.com/bluele/factory-go?tab=doc)factory-go is a fixtures replacement inspired by [factory_boy](https://github.com/FactoryBoy/factory_boy) and [factory_bot](https://github.com/thoughtbot/factory_bot).
It can be generated easily complex objects by using this, and maintain easily those objects generaters.
## Install
```
$ go get -u github.com/bluele/factory-go/factory
```## Usage
All of the following code on [examples](https://github.com/bluele/factory-go/tree/master/examples).
* [Define a simple factory](https://github.com/bluele/factory-go#define-a-simple-factory)
* [Use factory with random yet realistic values](https://github.com/bluele/factory-go#use-factory-with-random-yet-realistic-values)
* [Define a factory includes sub-factory](https://github.com/bluele/factory-go#define-a-factory-includes-sub-factory)
* [Define a factory includes a slice for sub-factory](https://github.com/bluele/factory-go#define-a-factory-includes-a-slice-for-sub-factory)
* [Define a factory includes sub-factory that contains self-reference](https://github.com/bluele/factory-go#define-a-factory-includes-sub-factory-that-contains-self-reference)
* [Define a sub-factory refers to parent factory](https://github.com/bluele/factory-go#define-a-sub-factory-refers-to-parent-factory)### Define a simple factory
Declare an factory has a set of simple attribute, and generate a fixture object.
```go
package mainimport (
"fmt"
"github.com/bluele/factory-go/factory"
)type User struct {
ID int
Name string
Location string
}// 'Location: "Tokyo"' is default value.
var UserFactory = factory.NewFactory(
&User{Location: "Tokyo"},
).SeqInt("ID", func(n int) (interface{}, error) {
return n, nil
}).Attr("Name", func(args factory.Args) (interface{}, error) {
user := args.Instance().(*User)
return fmt.Sprintf("user-%d", user.ID), nil
})func main() {
for i := 0; i < 3; i++ {
user := UserFactory.MustCreate().(*User)
fmt.Println("ID:", user.ID, " Name:", user.Name, " Location:", user.Location)
}
}
```Output:
```
ID: 1 Name: user-1 Location: Tokyo
ID: 2 Name: user-2 Location: Tokyo
ID: 3 Name: user-3 Location: Tokyo
```### Use factory with random yet realistic values.
Tests look better with random yet realistic values. For example, you can use [go-randomdata](https://github.com/Pallinder/go-randomdata) library to get them:
```go
package mainimport (
"fmt"
"github.com/Pallinder/go-randomdata"
"github.com/bluele/factory-go/factory"
)type User struct {
ID int
Name string
Location string
}// 'Location: "Tokyo"' is default value.
var UserFactory = factory.NewFactory(
&User{},
).SeqInt("ID", func(n int) (interface{}, error) {
return n, nil
}).Attr("Name", func(args factory.Args) (interface{}, error) {
return randomdata.FullName(randomdata.RandomGender), nil
}).Attr("Location", func(args factory.Args) (interface{}, error) {
return randomdata.City(), nil
})func main() {
for i := 0; i < 3; i++ {
user := UserFactory.MustCreate().(*User)
fmt.Println("ID:", user.ID, " Name:", user.Name, " Location:", user.Location)
}
}
```Output:
```
ID: 1 Name: Benjamin Thomas Location: Burrton
ID: 2 Name: Madison Davis Location: Brandwell
ID: 3 Name: Aubrey Robinson Location: Campden
```### Define a factory includes sub-factory
```go
package mainimport (
"fmt"
"github.com/bluele/factory-go/factory"
)type Group struct {
ID int
Name string
}type User struct {
ID int
Name string
Location string
Group *Group
}var GroupFactory = factory.NewFactory(
&Group{},
).SeqInt("ID", func(n int) (interface{}, error) {
return 2 - n%2, nil
}).Attr("Name", func(args factory.Args) (interface{}, error) {
group := args.Instance().(*Group)
return fmt.Sprintf("group-%d", group.ID), nil
})// 'Location: "Tokyo"' is default value.
var UserFactory = factory.NewFactory(
&User{Location: "Tokyo"},
).SeqInt("ID", func(n int) (interface{}, error) {
return n, nil
}).Attr("Name", func(args factory.Args) (interface{}, error) {
user := args.Instance().(*User)
return fmt.Sprintf("user-%d", user.ID), nil
}).SubFactory("Group", GroupFactory)func main() {
for i := 0; i < 3; i++ {
user := UserFactory.MustCreate().(*User)
fmt.Println(
"ID:", user.ID, " Name:", user.Name, " Location:", user.Location,
" Group.ID:", user.Group.ID, " Group.Name", user.Group.Name)
}
}
```Output:
```
ID: 1 Name: user-1 Location: Tokyo Group.ID: 1 Group.Name group-1
ID: 2 Name: user-2 Location: Tokyo Group.ID: 2 Group.Name group-2
ID: 3 Name: user-3 Location: Tokyo Group.ID: 1 Group.Name group-1
```### Define a factory includes a slice for sub-factory.
```go
package mainimport (
"fmt"
"github.com/bluele/factory-go/factory"
)type Post struct {
ID int
Content string
}type User struct {
ID int
Name string
Posts []*Post
}var PostFactory = factory.NewFactory(
&Post{},
).SeqInt("ID", func(n int) (interface{}, error) {
return n, nil
}).Attr("Content", func(args factory.Args) (interface{}, error) {
post := args.Instance().(*Post)
return fmt.Sprintf("post-%d", post.ID), nil
})var UserFactory = factory.NewFactory(
&User{},
).SeqInt("ID", func(n int) (interface{}, error) {
return n, nil
}).Attr("Name", func(args factory.Args) (interface{}, error) {
user := args.Instance().(*User)
return fmt.Sprintf("user-%d", user.ID), nil
}).SubSliceFactory("Posts", PostFactory, func() int { return 3 })func main() {
for i := 0; i < 3; i++ {
user := UserFactory.MustCreate().(*User)
fmt.Println("ID:", user.ID, " Name:", user.Name)
for _, post := range user.Posts {
fmt.Printf("\tPost.ID: %v Post.Content: %v\n", post.ID, post.Content)
}
}
}
```Output:
```
ID: 1 Name: user-1
Post.ID: 1 Post.Content: post-1
Post.ID: 2 Post.Content: post-2
Post.ID: 3 Post.Content: post-3
ID: 2 Name: user-2
Post.ID: 4 Post.Content: post-4
Post.ID: 5 Post.Content: post-5
Post.ID: 6 Post.Content: post-6
ID: 3 Name: user-3
Post.ID: 7 Post.Content: post-7
Post.ID: 8 Post.Content: post-8
Post.ID: 9 Post.Content: post-9
```### Define a factory includes sub-factory that contains self-reference.
```go
package mainimport (
"fmt"
"github.com/Pallinder/go-randomdata"
"github.com/bluele/factory-go/factory"
)type User struct {
ID int
Name string
CloseFriend *User
}var UserFactory = factory.NewFactory(
&User{},
)func init() {
UserFactory.SeqInt("ID", func(n int) (interface{}, error) {
return n, nil
}).Attr("Name", func(args factory.Args) (interface{}, error) {
return randomdata.FullName(randomdata.RandomGender), nil
}).SubRecursiveFactory("CloseFriend", UserFactory, func() int { return 2 }) // recursive depth is always 2
}func main() {
user := UserFactory.MustCreate().(*User)
fmt.Println("ID:", user.ID, " Name:", user.Name,
" CloseFriend.ID:", user.CloseFriend.ID, " CloseFriend.Name:", user.CloseFriend.Name)
// `user.CloseFriend.CloseFriend.CloseFriend ` depth is 3, so this value is always nil.
fmt.Printf("%v %v\n", user.CloseFriend.CloseFriend, user.CloseFriend.CloseFriend.CloseFriend)
}
```Output:
```
ID: 1 Name: Mia Williams CloseFriend.ID: 2 CloseFriend.Name: Joseph Wilson
&{3 Liam Wilson }
```### Define a sub-factory refers to parent factory
```go
package mainimport (
"fmt"
"github.com/bluele/factory-go/factory"
)type User struct {
ID int
Name string
Group *Group
}type Group struct {
ID int
Name string
Users []*User
}var UserFactory = factory.NewFactory(
&User{},
).SeqInt("ID", func(n int) (interface{}, error) {
return n, nil
}).Attr("Name", func(args factory.Args) (interface{}, error) {
user := args.Instance().(*User)
return fmt.Sprintf("user-%d", user.ID), nil
}).Attr("Group", func(args factory.Args) (interface{}, error) {
if parent := args.Parent(); parent != nil {
// if args have parent, use it.
return parent.Instance(), nil
}
return nil, nil
})var GroupFactory = factory.NewFactory(
&Group{},
).SeqInt("ID", func(n int) (interface{}, error) {
return 2 - n%2, nil
}).Attr("Name", func(args factory.Args) (interface{}, error) {
group := args.Instance().(*Group)
return fmt.Sprintf("group-%d", group.ID), nil
}).SubSliceFactory("Users", UserFactory, func() int { return 3 })func main() {
group := GroupFactory.MustCreate().(*Group)
fmt.Println("Group.ID:", group.ID)
for _, user := range group.Users {
fmt.Println("\tUser.ID:", user.ID, " User.Name:", user.Name, " User.Group.ID:", user.Group.ID)
}
}
```Output:
```
Group.ID: 1
User.ID: 1 User.Name: user-1 User.Group.ID: 1
User.ID: 2 User.Name: user-2 User.Group.ID: 1
User.ID: 3 User.Name: user-3 User.Group.ID: 1
```## Persistent models
Currently this project has no support for directly integration with ORM like [gorm](https://github.com/jinzhu/gorm), so you need to do manually.
Here is an example: https://github.com/bluele/factory-go/blob/master/examples/gorm_integration.go
# Author
**Jun Kimura**
*
*