{"id":16137304,"url":"https://github.com/goldziher/fabricator","last_synced_at":"2025-03-16T09:33:06.820Z","repository":{"id":57693192,"uuid":"432805778","full_name":"Goldziher/fabricator","owner":"Goldziher","description":"Golang factories for mock data generation","archived":false,"fork":false,"pushed_at":"2024-05-07T22:53:54.000Z","size":55,"stargazers_count":23,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-16T00:41:28.746Z","etag":null,"topics":["factories","factory","faker","go","golang","mock"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Goldziher.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2021-11-28T19:30:21.000Z","updated_at":"2025-03-15T14:14:46.000Z","dependencies_parsed_at":"2024-01-18T08:39:26.675Z","dependency_job_id":"3215b4bb-1a65-4976-a574-6afe884c6317","html_url":"https://github.com/Goldziher/fabricator","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Goldziher%2Ffabricator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Goldziher%2Ffabricator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Goldziher%2Ffabricator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Goldziher%2Ffabricator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Goldziher","download_url":"https://codeload.github.com/Goldziher/fabricator/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243852432,"owners_count":20358268,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["factories","factory","faker","go","golang","mock"],"created_at":"2024-10-09T23:26:16.002Z","updated_at":"2025-03-16T09:33:06.532Z","avatar_url":"https://github.com/Goldziher.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fabricator\n\n\u003cdiv align=\"center\"\u003e\n\n[![Go Report Card](https://goreportcard.com/badge/github.com/Goldziher/fabricator)](https://goreportcard.com/report/github.com/Goldziher/fabricator)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=Goldziher_fabricator\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=Goldziher_fabricator)\n[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=Goldziher_fabricator\u0026metric=coverage)](https://sonarcloud.io/summary/new_code?id=Goldziher_fabricator)\n[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=Goldziher_fabricator\u0026metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=Goldziher_fabricator)\n[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=Goldziher_fabricator\u0026metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=Goldziher_fabricator)\n[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=Goldziher_fabricator\u0026metric=security_rating)](https://sonarcloud.io/summary/new_code?id=Goldziher_fabricator)\n\n\u003c/div\u003e\n\nFabricator is a library for test data generation using structs and Go 1.18 generics. Its API is inspired by similar\nlibraries in other languages (e.g. [Pydantic-Factories](https://github.com/Goldziher/pydantic-factories)\n, [Interface-Forge](https://github.com/Goldziher/interface-forge)), which was not possible in Go before the introduction\nof generics.\n\n## Installation\n\n```shell\ngo get -u github.com/Goldziher/fabricator\n```\n\n## Example\n\n```golang\npackage some_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/Goldziher/fabricator\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype Pet struct {\n\tName    string\n\tSpecies string\n}\n\ntype Person struct {\n\tId          int\n\tFirstName   string\n\tLastName    string\n\tPets        []Pet\n\tFavoritePet Pet\n}\n\nvar personFactory = fabricator.New[Person](Person{})\n\nfunc TestSomething(t *testing.T) {\n\tpersonInstance := personFactory.Build()\n\tassert.IsType(t, Person{}, personInstance)\n\tassert.NotZero(t, personInstance.Id)\n\tassert.NotZero(t, personInstance.FirstName)\n\tassert.NotZero(t, personInstance.LastName)\n\tassert.NotZero(t, personInstance.Pets)\n\tassert.NotZero(t, personInstance.FavoritePet)\n}\n```\n\n## Defining Factories\n\nDefining a factory is very simple. Let's assume our app has a package called `types` where we define some struct, and\nanother package called `testhelpers` where we have some shared testing utilities.\n\n```golang\npackage types\n\ntype Pet struct {\n\tName    string\n\tSpecies string\n}\n\ntype Person struct {\n\tId          int\n\tFirstName   string\n\tLastName    string\n\tPets        []Pet\n\tFavoritePet Pet\n}\n```\n\nSince factories can be reused, it's a good idea to define them in a specific package from which they can be imported. In\nthe case of our imaginary app, this will be the `testhelpers` package:\n\n```golang\npackage testhelpers\n\nimport (\n\t\"github.com/Goldziher/fabricator\"\n\n\t\"github/someName/types\"\n)\n\nvar PersonFactory = fabricator.New[types.Person](types.Person{})\n```\n\nNote: If we have use for a Pet without its nesting inside Person, we might also want to define a PetFactory, but this is\nnot required in this example, since a slice of pets will be generated inside the `PersonFactory`.\n\nWe could also pass an options object when defining the factory, setting the factory's `Defaults` and\na `PersistenceHandler` function.\n\n### Factory Defaults\n\n```golang\npackage testhelpers\n\nimport (\n\t\"github.com/Goldziher/fabricator\"\n\n\t\"github/someName/types\"\n)\n\nvar PersonFactory = fabricator.New[types.Person](types.Person{}, fabricator.Options[types.Person]{\n\tDefaults: map[string]any{\n\t\t\"FirstName\": \"Moishe\",\n\t\t\"LastName\":  \"Zuchmir\",\n\t\t\"Pets\": func(iteration int, fieldName string) interface{} {\n\t\t\tpets := []types.Pet{}\n\t\t\tif iteration%2 == 0 {\n\t\t\t\tpets = append(pets, types.Pet{\n\t\t\t\t\t\"Flippy\",\n\t\t\t\t\t\"Dolphin\",\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn pets\n\t\t},\n\t},\n})\n```\n\nAs you can see above, the factory receives a `Defaults` object that maps struct field names, as map keys, to either\npre-specified values, or factory functions.\n\nWhile factory functions are more verbose, they are a powerful way to generate data and they can of course be shared\nacross different fields or even different factories.\n\nThe signature for a factory function is `func(iteration int, fieldName string) interface{}`, with `iteration` being the\ncurrent value of the factory's internal counter, and `fieldName` being the name of the specific struct field for which a\nvalue is being generated.\n\n### Persistence Handler\n\nWhen defining a factory, you can pass a `PersistenceHandler`, that is, a struct conforming to\nthe `fabricator.PersistenceHandler` interface:\n\n```golang\npackage fabricator\n\ntype PersistenceHandler[T any] interface {\n\tSave(instance T) T\n\tSaveMany(instance []T) []T\n}\n```\n\nWith a persistence handler defined for the factory, you can call the `.Create` and `.CreateBatch` methods which build\nand then persist the data in one command. For example:\n\n```golang\npackage testhelpers\n\nimport (\n\t\"github.com/Goldziher/fabricator\"\n\n\t\"github/someName/db\"\n\t\"github/someName/types\"\n)\n\ntype MyPersistenceHandler[T any] struct{}\n\nfunc (handler MyPersistenceHandler[T]) Save(instance T) T {\n\tdb.Create(\u0026instance)\n\treturn instance\n}\n\nfunc (handler MyPersistenceHandler[T]) SaveMany(instances []T) []T {\n\tdb.Create(\u0026instances)\n\treturn instances\n}\n\nvar PersonFactory = fabricator.New[types.Person](types.Person{}, fabricator.Options[types.Person]{\n\tPersistenceHandler: MyPersistenceHandler[types.Person]{},\n})\n```\n\n## Factory Methods\n\nOnce a factory is defined it exposes the following methods:\n\n### Build\n\n`func (factory *Factory[T]) Build(overrides ...map[string]any) T`\n\nBuild creates a single instance of the factory's model:\n\n```golang\npackage test_something\n\nimport (\n\t\"testing\"\n\n\t\"github/someName/testhelpers\"\n)\n\nfunc TestSomething(t *testing.T) {\n\tperson := testhelpers.PersonFactory.Build()\n\t// ...\n}\n```\n\nYou can pass to build a mapping of override values, this works exactly like the factory defaults, for example:\n\n```golang\npackage test_something\n\nimport (\n\t\"testing\"\n\n\t\"github/someName/types\"\n\t\"github/someName/testhelpers\"\n)\n\nfunc TestSomething(t *testing.T) {\n\tperson := testhelpers.PersonFactory.Build(map[string]any{\n\t\t\"FirstName\": \"Moishe\",\n\t\t\"LastName\":  \"Zuchmir\",\n\t\t\"Pets\": func(iteration int, fieldName string) interface{} {\n\t\t\tpets := []types.Pet{}\n\t\t\tif iteration%2 == 0 {\n\t\t\t\tpets = append(pets, types.Pet{\n\t\t\t\t\t\"Flippy\",\n\t\t\t\t\t\"Dolphin\",\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn pets\n\t\t},\n\t})\n\t// ...\n}\n```\n\n### Batch\n\n`func (factory *Factory[T]) Batch(size int, overrides ...map[string]any) []T`\n\nBatch builds a slice of instances of a given size:\n\n```golang\npackage test_something\n\nimport (\n\t\"testing\"\n\t\"github.com/stretchr/testify/assert\"\n\n\t\"github/someName/types\"\n\t\"github/someName/testhelpers\"\n)\n\nfunc TestSomething(t *testing.T) {\n\tpeople := testhelpers.PersonFactory.Batch(5)\n\tassert.Len(t, people, 5)\n}\n```\n\nNote: You can pass to batch overrides the same as you can for build\n\n### Create\n\n`func (factory *Factory[T]) Create(overrides ...map[string]any) T`\n\nIf a factory defines a [Persistence Handler](#persistence-handler) you can use `.Create` to build and persist a model\ninstance. Create is identical to `.Build` in terms of its API.\n\n```golang\npackage test_something\n\nimport (\n\t\"testing\"\n\n\t\"github/someName/testhelpers\"\n)\n\nfunc TestSomething(t *testing.T) {\n\tperson := testhelpers.PersonFactory.Create() // person is persisted using the PersistanceHandler's .Save method\n\t// ...\n}\n```\n\n### CreateBatch\n\n`func (factory *Factory[T]) CreateBatch(size int, overrides ...map[string]any) []T`\n\nIf a factory defines a [Persistence Handler](#persistence-handler) you can use `.CreateBatch` to build and persist a\nslice of model instances of a given size. CreateBatch is identical to `.Batch` in terms of its API:\n\n```golang\npackage test_something\n\nimport (\n\t\"testing\"\n\n\t\"github/someName/testhelpers\"\n)\n\nfunc TestSomething(t *testing.T) {\n\tpeople := testhelpers.PersonFactory.CreateBatch(5) // person is persisted using the PersistanceHandler's .SaveMany method\n\t// ...\n}\n```\n\n## Using Struct Tags\n\nFabricator uses the excellent [faker](https://github.com/bxcodec/faker) library to generate mock data. As such, you can\nuse the faker struct tags to control the data generation, please consult the documentation for that library to see the\navailable tags.\n\n## Contribution\n\nThis library is open to contributions. Please consult the [Contribution Guide](CONTRIBUTING.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoldziher%2Ffabricator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoldziher%2Ffabricator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoldziher%2Ffabricator/lists"}