Skip to content

DB Fixtures for functional option pattern based models

License

Notifications You must be signed in to change notification settings

akm/go-fixtures

Folders and files

NameName
Last commit message
Last commit date

Latest commit

33b1a8a · Nov 17, 2024

History

44 Commits
Nov 17, 2024
Nov 9, 2024
Nov 8, 2024
Nov 8, 2024
Nov 8, 2024
Nov 10, 2024
Nov 9, 2024
Nov 8, 2024
Nov 9, 2024
Nov 8, 2024
Nov 8, 2024
Nov 9, 2024

Repository files navigation

github.com/akm/go-fixtures

  • module name: github.com/akm/go-fixtures
  • package name: fixtures

Overview

fixtures package simplifies database operations in tests using models based on Functional Options Pattern. It integrates with GORM for object manipulation but remains agnostic to the specific models you use. Test fixtures can be defined directly in Go code.

ORM support

GORM

fixtures works seamlessly with models designed for GORM, making it straightforward to create and manage fixtures.

sqlc

Even if you use sqlc to generate models, fixtures is compatible. The structure of sqlc-generated models is similar to GORM models, making the integration easy. For example:

Other ORMs

Even if you're using another ORM or none at all, fixtures allows you to define plain fixture models. Feel free to reach out if you encounter any issues.

Install

go get github.com/akm/go-fixtures

How to Create Models and Fixtures

  1. Define fixture models.
  2. Add functional Options types for the models.
  3. Create a Fixtures struct for each model.
  4. Use the defined fixtures in your tests.

1. Define Fixture Models

If you already have a model, you can embed it. Otherwise, define a new model or skip this step if it's unnecessary.

Original Model

type Article struct {
	ID        int
	CreatedAt time.Time
	UpdatedAt time.Time
	AuthorID  int
	Title     string
	Url       string
}

Fixture Model

type Article struct {
	models.Article

	Author *users.User
}

For examples, see:

2. Add Functional Option Types

Define Option types and corresponding functions using the Functional Option Pattern. Refer to Rob Pike's article and Dave Cheney's article.

type Option = func(*Article)

func Title(v string) Option { return func(a *Article) { a.Title = v } }
func Url(v string) Option   { return func(a *Article) { a.Url = v } }
func AuthorID(v int) Option { return func(a *Article) { a.AuthorID = v } }
func Author(v *users.User) Option {
	return func(a *Article) {
		a.Author = v
		if v != nil {
			a.AuthorID = v.ID
		} else {
			a.AuthorID = 0
		}
	}
}

You can instantiate models using fixtures.New[T any] or fixtures.NewWithDefaults[T any].

3. Make Fixtures for each fixture model

Define the Fixtures Struct

type Fixtures struct {
	*fixtures.Fixtures[Article]
	Users *users.Fixtures
}

Embed *fixtures.Fixtures to inherit its methods New and Get. Include related fixture types as fields if fixture model refers other models.

Add a Constructor Function

func NewFixtures() *Fixtures {
	r := &Fixtures{
		Users: users.NewFixtures(),
	}
	r.Fixtures = fixtures.NewFixtures[Article](r)
	return r
}

Add NewXXX Methods for each Fixture.

Define methods to create specific fixture instances:

func (f *Fixtures) NewFiveRules(opts ...Option) *Article {
	return fixtures.NewWithDefaults(opts,
		Author(f.Users.RobPike()),
		Title("Rob Pike's 5 Rules of Programming"),
		Url("https://users.ece.utexas.edu/~adnan/pike.html"),
	)
}

These methods must:

  • Be variadic to accept zero or more Option s.
  • Return a pointer to the model.

Add Fixture Retrieval Methods

func (f *Fixtures) FiveRules(opts ...Option) *Article  { return f.Get("FiveRules", opts...) }

This is a fixed form. You can change the method name, but the first argument of f.Get must match the method name.

For examples, see:

4. Use Fixtures

Setup fixtures.DB

fixtures uses GORM.

To set up fixtures.DB, you need to provide a gorm.Dialector and optionally one or more gorm.Options. If you use a specific database (e.g., MySQL), make sure to install the corresponding GORM driver. For instance, for MySQL, run:

go get gorm.io/driver/mysql

Here’s an example of setting up fixtures.DB:

	gormLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags),
		logger.Config{SlowThreshold: time.Second, LogLevel: logger.Info},
	)

	fx := fixtures.NewDB(
		mysql.New(mysql.Config{Conn: db}),
		&gorm.Config{Logger: gormLogger},
	)(t)

Deleting Records from a Table

To delete all records from specific tables, use fx.DeleteFromTable. Pass instances of your model with zero-value fields as arguments:

fx.DeleteFromTable(t, &articles.Article{}, &users.User{})

Inserting Fixture Data

To insert fixture data, create an instance of your Fixtures struct and call fx.Create, passing the fixture instances you want to add to the database.

	fxArticles := articles.NewFixtures()
	fx.Create(t,
		fxArticles.FiveRules(),
		fxArticles.GoProverbs(),
		fxArticles.ABriefIntroduction(),
	)

Additional Details

For more information on setting up and using GORM, see Connecting to a Database. You can also refer to examples/tests/example_test.go for a complete implementation.

Test

You can view the test results in GitHub Actions.GitHub Actions.

License

MIT License

About

DB Fixtures for functional option pattern based models

Resources

License

Stars

Watchers

Forks

Packages

No packages published