• Stars
    star
    356
  • Rank 119,446 (Top 3 %)
  • Language
    Go
  • License
    MIT License
  • Created about 9 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A library for setting up Golang objects inspired by factory_bot.

factory-go

Test GoDoc

factory-go is a fixtures replacement inspired by factory_boy and 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.

Define a simple factory

Declare an factory has a set of simple attribute, and generate a fixture object.

package main

import (
  "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 library to get them:

package main

import (
  "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

package main

import (
  "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.

package main

import (
  "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.

package main

import (
  "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 <nil>} <nil>

Define a sub-factory refers to parent factory

package main

import (
  "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, 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

More Repositories

1

gcache

An in-memory cache library for golang. It supports multiple eviction policies: LRU, LFU, ARC
Go
2,439
star
2

slack

Golang client for the Slack API. **NOTE: This project is already archived, so we recommend that you use https://github.com/slack-go/slack instead.**
Go
185
star
3

gforms

A flexible forms validation and rendering library for golang web development.Inspired by django-forms and wtforms.
Go
124
star
4

mecab-golang

A golang wrapper for mecab.
Go
36
star
5

redis-semaphore

A distributed semaphore and mutex built on Redis.
Python
35
star
6

react-go

Go wrapper around the React and JSX.
Go
31
star
7

adblock

Golang parser for Adblock Plus filters
Go
19
star
8

Flask-request-params

Flask-request-params provides Rails-like interface to HTTP Request Parameters for Flask.
Python
10
star
9

go-flow

go-flow is a Golang library that helps you to create a complex flow of batch jobs.
Go
6
star
10

zapslack

Slack Hook for zap
Go
6
star
11

gsignal

Golang library for monitoring asynchronously signals.
Go
4
star
12

gosem

gosem provides multiple semaphore functions. Currently supports inmemory, redis implementation.
Go
4
star
13

go-v7

Go binding to javascript engine v7.
C
4
star
14

Flask-jsonrpc-over-websocket-example

Example flask code to implement jsonrpc over websocket.
Python
3
star
15

randutil

Random variable utility library for golang. Inspired by python random module.
Go
3
star
16

psort

Partial sorting for golang
Go
2
star
17

logrus_slack

Slack Hooks for Logrus
Go
2
star
18

Gistpy

Command line client for gist.
Python
2
star
19

go-subprocess

[WIP] A convenience wrapper around the `os/exec` module.
Go
2
star
20

cetd

Content Extraction via Text Density (CETD) program provides algorithms to detect and remove the additional content
C++
2
star
21

Twister

Twitter Streaming Server.
Python
1
star
22

vermouth

Go
1
star
23

dynamodb

Golang dynamodb library.
Go
1
star
24

gcoding

An encoding library for golang.
Go
1
star
25

greq

Yet another HTTP client library for golang.
Go
1
star
26

rkvs

simple raft-based kvs
Go
1
star
27

Dym

Show the candidate string such as "Did you mean this?" on git.
Python
1
star
28

gen-validator

Go
1
star
29

DM

Data mining library.
C++
1
star
30

golang-swig-example

swig example codes for golang.
C++
1
star
31

pystol

Python
1
star
32

gocache

[Deprecated] Cache module for golang. See https://github.com/bluele/gcache
Go
1
star
33

FileTransaction

File transaction for python2.x
Python
1
star
34

go-semaphore

Implements basic semaphore and time limited semaphore on go language.
Go
1
star
35

ExtractWord

Python
1
star
36

fsobserve

Yet another file system observer. Supports Linux, OSX, Windows, and etc.
Go
1
star
37

ngram

Rust
1
star
38

interchain-simple-packet

Go
1
star
39

Lamia

Cache Module for Python2.x
Python
1
star
40

forge-tx-replay

A small library for Forge that makes it easy to replay transactions and inspect the contract code and state
Solidity
1
star
41

interchain-packet-router

A very experimental project to define a packet router on interchain
Go
1
star
42

StringMatching

Approximate string matching
1
star
43

PyCliper

Python Tkinter-GUI Application
Python
1
star