GithubHelp home page GithubHelp logo

k-yomo / fixtory Goto Github PK

View Code? Open in Web Editor NEW
86.0 2.0 5.0 95 KB

Type-safe, DRY, flexible test fixture factory based on Go 1.18+ Generics

License: MIT License

Makefile 1.54% Go 98.46%
go fixture-factory factory-bot fixture-replacement factory-boy golang generics

fixtory's Introduction

License: MIT Main Workflow codecov Go Report Card

Fixtory is a test fixture factory which initializes type-safe, DRY, flexible fixtures with the power of Generics.

By using Fixtory...

  • No more redundant repeated field value setting
  • No more type assertion to convert from interface
  • No more error handling when building fixture
  • No more exhaustion to just prepare test data

Installation

$ go get github.com/k-yomo/fixtory/v2

Getting started

Complete code is in example.

Use factory to initialize fixtures

// Author represents article's author
type Author struct {
    ID   int
    Name string
}

// Article represents article
type Article struct {
    ID                 int
    Title              string
    Body               string
    AuthorID           int
    PublishScheduledAt time.Time
    PublishedAt        time.Time
    Status             ArticleStatus
    LikeCount          int
}

var authorBluePrint = func(i int, last Author) Author {
	num := i + 1
	return Author{
		ID:   num,
		Name: fmt.Sprintf("Author %d", num),
	}
}

var articleBluePrint = func(i int, last Article) Article {
	num := i + 1
	return Article{
		ID:                 num,
		Title:              fmt.Sprintf("Article %d", i+1),
		AuthorID:           num,
		PublishScheduledAt: time.Now().Add(-1 * time.Hour),
		PublishedAt:        time.Now().Add(-1 * time.Hour),
		LikeCount:          15,
	}
}


func TestArticleList_SelectAuthoredBy(t *testing.T) {
    authorFactory := fixtory.NewFactory(t, Author{})
    articleFactory := fixtory.NewFactory(t, Article{})

    author1, author2 := authorFactory.NewBuilder(authorBluePrint).Build2()
    articlesAuthoredBy1 := articleFactory.NewBuilder(articleBluePrint, Article{AuthorID: author1.ID}).BuildList(4)
    articleAuthoredBy2 := articleFactory.NewBuilder(articleBluePrint, Article{AuthorID: author2.ID}).Build()

    type args struct {
        authorID int
    }
    tests := []struct {
        name string
        list ArticleList
        args args
        want ArticleList
    }{
        {
            name: "returns articles authored by author 1",
            list: append(articlesAuthoredBy1, articleAuthoredBy2),
            args: args{authorID: author1.ID},
            want: articlesAuthoredBy1,
        },
        {
            name: "returns articles authored by author 2",
            list: append(articlesAuthoredBy1, articleAuthoredBy2),
            args: args{authorID: author2.ID},
            want: ArticleList{articleAuthoredBy2},
        },
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := tt.list.SelectAuthoredBy(tt.args.authorID); !reflect.DeepEqual(got, tt.want) {
                t.Errorf("SelectAuthoredBy() = %v, want %v", got, tt.want)
            }
        })
    }
}

How it works

There are 4 layers in the process of initializing fixture in fixtory. The layers are stacked and each one is a delta of the changes from the previous layer like Dockerfile.

1. Blueprint

Blueprint is the base of fixture(like FROM in Dockerfile) and called first. You need to implement blueprint function to meet generated blueprint type (like below) It should return instance with generic field values.

type TestArticleBluePrintFunc func(i int, last Article) Article

2. Traits

To overwrite some fields, you can use traits. Traits are applied in the order of arguments to all fixtures. ※ Only non-zero value will be set.

//  Repeatedly used trait would be better to define as global variable.
var articleTraitPublished = Article{
	Status:             ArticleStatusOpen,
	PublishScheduledAt: time.Now().Add(-1 * time.Hour),
	PublishedAt:        time.Now().Add(-1 * time.Hour),
	LikeCount:          15,
}

// recently published articles
articles:= articleFactory.NewBuilder(
               nil, 
               articleTraitPublished,
               Article{AuthorID: 5, PublishedAt: time.Now().Add(-1 * time.Minute)},
           ).BuildList(2)

3. Each Param

When you want to overwrite a specific fixture in the list, use EachParam. Each Param overwrites the same index struct as parameter. ※ Only non-zero value will be set.

articleFactory := NewArticleFactory(t)
articles := articleFactory.NewBuilder(nil, Article{Title: "test article"})
                .EachParam(Article{AuthorID: 1}, Article{AuthorID: 2}, Article{AuthorID: 2})
                .BuildList(3)

4. Zero

Since there is no way to distinguish default zero value or intentionally set zero in params, you can overwrite fields with zero value like below, and it will be applied at the last minute.

articleFactory := NewArticleFactory(t)
// AuthorID will be overwritten with zero value.
articles := articleFactory.NewBuilder(articleBluePrint, Article{AuthorID: author1.ID}).
                Zero(ArticleAuthorIDField).
                BuildList(4)

fixtory's People

Contributors

dependabot[bot] avatar k-yomo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

fixtory's Issues

Output flag problem

When set -output parameter as a name of file (without any ./ before), occurs error by os.MkdirAll trying to create empty dir:

initialize writer:
    github.com/k-yomo/fixtory.Generate
        /home/masai/go/pkg/mod/github.com/k-yomo/[email protected]/generate.go:112
  - create directory: mkdir : no such file or directory Output Dir: ``:
    main.main.func1
        /home/username/go/pkg/mod/github.com/k-yomo/[email protected]/cmd/fixtory/main.go:61
  - mkdir : no such file or directory

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.