buildergen

Usage

Step 1: Install this package

go install github.com/Jh123x/buildergen@latest

Install this package start using it

Step 2: Use the package

There are multiple ways to use this package

Step 2a: Using go generate

Write the go generate comment as shown in the example below.

package examples

import "github.com/Jh123x/buildergen/examples/nested"

//go:generate buildergen -src=./test.go -name Person

type Person struct {
	ID        int
	Name      string
	Email     *string // Optional field
	PhoneBook []*Contact
	MapVal    map[string]string `json:"map_val"`
	T         nested.Test
}

type Contact struct {
	Name  string
	Phone string
}

Step 2b: Using the command line

Another way to use BuilderGen using the command line.

buildergen -src=./examples/test.go -name Person

This will generate the same builder as the go:generate method.

Step 2c: Using the yaml config

Another way to use BuilderGen is to use a config file

buildergen --config ./path/to/config.yaml

The config file should look something like this

configs:
- source: ./internal/cmd/ttypes.go
  name: Config
- source: ./internal/cmd/ttypes_test.go
  name: testCase
  destination: ./internal/cmd/ttypes_builder_test.go
- source: ./examples/benchmark/benchmark.go
  name: Data
  mode: DEFAULT # Default mode uses golang built in AST
- source: ./examples/person.go
  name: Person
  mode: FAST # Fast mode uses custom parsers but may have more error edge cases. Use this when generation speed is important.

This use case is more suitable for those who wants to build a builder for structs in other libraries but want to store the mocks directly within the a mocks/test directory.

Step 3: Using the builder

After running the go generate, the generated file will look something like this.

// Code generated by BuilderGen
package examples

import (
	"github.com/Jh123x/buildergen/examples/nested"
)

type PersonBuilder struct {
	ID        int
	Name      string
	Email     *string
	PhoneBook []*Contact
	MapVal    map[string]string `json:"map_val"`
	T         nested.Test
}

func NewPersonBuilder(b *Person) *PersonBuilder {
	return &PersonBuilder{
		ID:        b.ID,
		Name:      b.Name,
		Email:     b.Email,
		PhoneBook: b.PhoneBook,
		MapVal:    b.MapVal,
		T:         b.T,
	}
}

func (b *PersonBuilder) WithID(id int) *PersonBuilder {
	b.ID = id
	return b
}

func (b *PersonBuilder) WithName(name string) *PersonBuilder {
	b.Name = name
	return b
}

func (b *PersonBuilder) WithEmail(email *string) *PersonBuilder {
	b.Email = email
	return b
}

func (b *PersonBuilder) WithPhoneBook(phonebook []*Contact) *PersonBuilder {
	b.PhoneBook = phonebook
	return b
}

func (b *PersonBuilder) WithMapVal(mapval map[string]string) *PersonBuilder {
	b.MapVal = mapval
	return b
}

func (b *PersonBuilder) WithT(t nested.Test) *PersonBuilder {
	b.T = t
	return b
}

func (b *PersonBuilder) Build() *Person {
	return &Person{
		ID:        b.ID,
		Name:      b.Name,
		Email:     b.Email,
		PhoneBook: b.PhoneBook,
		MapVal:    b.MapVal,
		T:         b.T,
	}
}

Step 4: Use the builder

Use the builder wherever you need it.


var defaultPerson = &Person{
	ID: 1,
	Name: "John",
	Email: nil,
}

...
func TestXXX(t *testing.T){
	clonedPerson := NewPersonBuilder(defaultPerson).WithID(12).WithName("Johnny").Build() // ID and Name changes
	...
	// Use clonedPerson
}