{"id":13575606,"url":"https://github.com/pashagolub/pgxmock","last_synced_at":"2025-05-15T02:08:14.776Z","repository":{"id":37409909,"uuid":"336344331","full_name":"pashagolub/pgxmock","owner":"pashagolub","description":"pgx mock driver for golang to test database interactions ","archived":false,"fork":false,"pushed_at":"2025-03-18T13:15:14.000Z","size":342,"stargazers_count":459,"open_issues_count":0,"forks_count":53,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-14T00:58:16.280Z","etag":null,"topics":["database","go","golang","pgx","postgres","postgresql","sqlmock","tdd"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pashagolub.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"pashagolub","custom":["https://revolut.me/pavlogolub"]}},"created_at":"2021-02-05T17:38:28.000Z","updated_at":"2025-04-13T17:59:46.000Z","dependencies_parsed_at":"2023-10-17T06:32:51.977Z","dependency_job_id":"9e751122-e4a1-468a-82f4-8f5d7d8c8fa5","html_url":"https://github.com/pashagolub/pgxmock","commit_stats":{"total_commits":222,"total_committers":21,"mean_commits":"10.571428571428571","dds":"0.32432432432432434","last_synced_commit":"9ce831316bcb3c3b70746e05c7a16ef9deef58e2"},"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pashagolub%2Fpgxmock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pashagolub%2Fpgxmock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pashagolub%2Fpgxmock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pashagolub%2Fpgxmock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pashagolub","download_url":"https://codeload.github.com/pashagolub/pgxmock/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254259384,"owners_count":22040820,"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":["database","go","golang","pgx","postgres","postgresql","sqlmock","tdd"],"created_at":"2024-08-01T15:01:02.528Z","updated_at":"2025-05-15T02:08:14.725Z","avatar_url":"https://github.com/pashagolub.png","language":"Go","funding_links":["https://github.com/sponsors/pashagolub","https://revolut.me/pavlogolub"],"categories":["Development","测试","Template Engines","Go","Testing"],"sub_categories":["Go Libraries","Mock"],"readme":"[![Go Reference](https://pkg.go.dev/badge/github.com/pashagolub/pgxmock.svg)](https://pkg.go.dev/github.com/pashagolub/pgxmock/v4)\n[![Go Report Card](https://goreportcard.com/badge/github.com/pashagolub/pgxmock)](https://goreportcard.com/report/github.com/pashagolub/pgxmock/v4)\n[![Coverage Status](https://coveralls.io/repos/github/pashagolub/pgxmock/badge.svg?branch=master)](https://coveralls.io/github/pashagolub/pgxmock?branch=master)\n[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)\n\n# pgx driver mock for Golang\n\n**pgxmock** is a mock library implementing [pgx - PostgreSQL Driver and Toolkit](https://github.com/jackc/pgx/). \nIt's based on the well-known [sqlmock](https://github.com/DATA-DOG/go-sqlmock) library for `sql/driver`.\n\n**pgxmock** has one and only purpose - to simulate **pgx** behavior in tests, without needing a real database connection. It helps to maintain correct **TDD** workflow.\n\n- written based on **go1.21** version;\n- does not require any modifications to your source code;\n- has strict by default expectation order matching;\n- has no third party dependencies except **pgx** packages.\n\n## Install\n\n    go get github.com/pashagolub/pgxmock/v4\n\n## Documentation and Examples\n\nVisit [godoc](http://pkg.go.dev/github.com/pashagolub/pgxmock/v4) for general examples and public api reference.\n\nSee implementation examples:\n\n- [the simplest one](https://github.com/pashagolub/pgxmock/tree/master/examples/basic)\n- [blog API server](https://github.com/pashagolub/pgxmock/tree/master/examples/blog)\n\n\n### Something you may want to test\n\n``` go\npackage main\n\nimport (\n\t\"context\"\n\n\tpgx \"github.com/jackc/pgx/v5\"\n)\n\ntype PgxIface interface {\n\tBegin(context.Context) (pgx.Tx, error)\n\tClose(context.Context) error\n}\n\nfunc recordStats(db PgxIface, userID, productID int) (err error) {\n\tif tx, err := db.Begin(context.Background()); err != nil {\n\t\treturn\n\t}\n\tdefer func() {\n\t\tswitch err {\n\t\tcase nil:\n\t\t\terr = tx.Commit(context.Background())\n\t\tdefault:\n\t\t\t_ = tx.Rollback(context.Background())\n\t\t}\n\t}()\n\tsql := \"UPDATE products SET views = views + 1\"\n\tif _, err = tx.Exec(context.Background(), sql); err != nil {\n\t\treturn\n\t}\n\tsql = \"INSERT INTO product_viewers (user_id, product_id) VALUES ($1, $2)\"\n\tif _, err = tx.Exec(context.Background(), sql, userID, productID); err != nil {\n\t\treturn\n\t}\n\treturn\n}\n\nfunc main() {\n\t// @NOTE: the real connection is not required for tests\n\tdb, err := pgx.Connect(context.Background(), \"postgres://rolname@hostname/dbname\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tdefer db.Close(context.Background())\n\n\tif err = recordStats(db, 1 /*some user id*/, 5 /*some product id*/); err != nil {\n\t\tpanic(err)\n\t}\n}\n```\n\n### Tests with pgxmock\n\n``` go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/pashagolub/pgxmock/v4\"\n)\n\n// a successful case\nfunc TestShouldUpdateStats(t *testing.T) {\n\tmock, err := pgxmock.NewPool()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer mock.Close()\n\n\tmock.ExpectBegin()\n\tmock.ExpectExec(\"UPDATE products\").\n\t\tWillReturnResult(pgxmock.NewResult(\"UPDATE\", 1))\n\tmock.ExpectExec(\"INSERT INTO product_viewers\").\n\t\tWithArgs(2, 3).\n\t\tWillReturnResult(pgxmock.NewResult(\"INSERT\", 1))\n\tmock.ExpectCommit()\n\n\t// now we execute our method\n\tif err = recordStats(mock, 2, 3); err != nil {\n\t\tt.Errorf(\"error was not expected while updating: %s\", err)\n\t}\n\n\t// we make sure that all expectations were met\n\tif err := mock.ExpectationsWereMet(); err != nil {\n\t\tt.Errorf(\"there were unfulfilled expectations: %s\", err)\n\t}\n}\n\n// a failing test case\nfunc TestShouldRollbackStatUpdatesOnFailure(t *testing.T) {\n\tmock, err := pgxmock.NewPool()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tdefer mock.Close()\n\n\tmock.ExpectBegin()\n\tmock.ExpectExec(\"UPDATE products\").\n\t\tWillReturnResult(pgxmock.NewResult(\"UPDATE\", 1))\n\tmock.ExpectExec(\"INSERT INTO product_viewers\").\n\t\tWithArgs(2, 3).\n\t\tWillReturnError(fmt.Errorf(\"some error\"))\n\tmock.ExpectRollback()\n\n\t// now we execute our method\n\tif err = recordStats(mock, 2, 3); err == nil {\n\t\tt.Errorf(\"was expecting an error, but there was none\")\n\t}\n\n\t// we make sure that all expectations were met\n\tif err := mock.ExpectationsWereMet(); err != nil {\n\t\tt.Errorf(\"there were unfulfilled expectations: %s\", err)\n\t}\n}\n```\n\n## Customize SQL query matching\n\nThere were plenty of requests from users regarding SQL query string validation or different matching option.\nWe have now implemented the `QueryMatcher` interface, which can be passed through an option when calling\n`pgxmock.New` or `pgxmock.NewWithDSN`.\n\nThis now allows to include some library, which would allow for example to parse and validate SQL AST.\nAnd create a custom QueryMatcher in order to validate SQL in sophisticated ways.\n\nBy default, **pgxmock** is preserving backward compatibility and default query matcher is `pgxmock.QueryMatcherRegexp`\nwhich uses expected SQL string as a regular expression to match incoming query string. There is an equality matcher:\n`QueryMatcherEqual` which will do a full case sensitive match.\n\nIn order to customize the QueryMatcher, use the following:\n\n``` go\n\tmock, err := pgxmock.New(context.Background(), pgxmock.QueryMatcherOption(pgxmock.QueryMatcherEqual))\n```\n\nThe query matcher can be fully customized based on user needs. **pgxmock** will not\nprovide a standard sql parsing matchers.\n\n## Matching arguments like time.Time\n\nThere may be arguments which are of `struct` type and cannot be compared easily by value like `time.Time`. In this case\n**pgxmock** provides an [Argument](https://pkg.go.dev/github.com/pashagolub/pgxmock/v4#Argument) interface which\ncan be used in more sophisticated matching. Here is a simple example of time argument matching:\n\n``` go\ntype AnyTime struct{}\n\n// Match satisfies sqlmock.Argument interface\nfunc (a AnyTime) Match(v interface{}) bool {\n\t_, ok := v.(time.Time)\n\treturn ok\n}\n\nfunc TestAnyTimeArgument(t *testing.T) {\n\tt.Parallel()\n\tdb, mock, err := New()\n\tif err != nil {\n\t\tt.Errorf(\"an error '%s' was not expected when opening a stub database connection\", err)\n\t}\n\tdefer db.Close()\n\n\tmock.ExpectExec(\"INSERT INTO users\").\n\t\tWithArgs(\"john\", AnyTime{}).\n\t\tWillReturnResult(NewResult(1, 1))\n\n\t_, err = db.Exec(\"INSERT INTO users(name, created_at) VALUES (?, ?)\", \"john\", time.Now())\n\tif err != nil {\n\t\tt.Errorf(\"error '%s' was not expected, while inserting a row\", err)\n\t}\n\n\tif err := mock.ExpectationsWereMet(); err != nil {\n\t\tt.Errorf(\"there were unfulfilled expectations: %s\", err)\n\t}\n}\n```\n\nIt only asserts that argument is of `time.Time` type.\n\n## Run tests\n\n    go test -race\n\n## Contributions\n\nFeel free to open a pull request. Note, if you wish to contribute an extension to public (exported methods or types) -\nplease open an issue before, to discuss whether these changes can be accepted. All backward incompatible changes are\nand will be treated cautiously\n\n## License\n\nThe [three clause BSD license](http://en.wikipedia.org/wiki/BSD_licenses)\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=pashagolub/pgxmock\u0026type=Date)](https://star-history.com/#pashagolub/pgxmock\u0026Date)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpashagolub%2Fpgxmock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpashagolub%2Fpgxmock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpashagolub%2Fpgxmock/lists"}