{"id":30288412,"url":"https://github.com/go-spring/gs-mock","last_synced_at":"2026-05-20T19:40:22.129Z","repository":{"id":299042647,"uuid":"1001897103","full_name":"go-spring/gs-mock","owner":"go-spring","description":"A modern and type-safe mocking library for Go with full support for generics.","archived":false,"fork":false,"pushed_at":"2025-08-02T02:02:16.000Z","size":144,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-09T21:51:51.828Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/go-spring.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":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-14T09:15:24.000Z","updated_at":"2025-08-02T02:01:58.000Z","dependencies_parsed_at":"2025-06-14T10:29:36.725Z","dependency_job_id":"095dc635-414d-4d8f-9ad9-47431adbe8bb","html_url":"https://github.com/go-spring/gs-mock","commit_stats":null,"previous_names":["go-spring/mock","go-spring/gs-mock"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/go-spring/gs-mock","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-spring%2Fgs-mock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-spring%2Fgs-mock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-spring%2Fgs-mock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-spring%2Fgs-mock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/go-spring","download_url":"https://codeload.github.com/go-spring/gs-mock/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-spring%2Fgs-mock/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270781210,"owners_count":24643807,"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","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2025-08-16T22:36:40.801Z","updated_at":"2026-05-20T19:40:22.123Z","avatar_url":"https://github.com/go-spring.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gs-mock\n\n\u003cdiv\u003e\n   \u003cimg src=\"https://img.shields.io/github/license/go-spring/gs-mock\" alt=\"license\"/\u003e\n   \u003ca href=\"https://codecov.io/gh/go-spring/gs-mock\" \u003e \n      \u003cimg src=\"https://codecov.io/gh/go-spring/gs-mock/branch/main/graph/badge.svg?token=SX7CV1T0O8\" alt=\"test-coverage\"/\u003e\n   \u003c/a\u003e\n   \u003ca href=\"https://deepwiki.com/go-spring/gs-mock\"\u003e\u003cimg src=\"https://deepwiki.com/badge.svg\" alt=\"Ask DeepWiki\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n[English](README.md) | [中文](README_CN.md)\n\n\u003e The project has been officially released, welcome to use!\n\n`gs-mock` is a modern, type-safe Go mock library with **full support for generics**.\nIt addresses the shortcomings of traditional Go mock tools in terms of **type safety** and **usability**,\nand natively supports concurrent testing through `context.Context` propagation.\n\n`gs-mock` supports mocking the following targets:\n\n* Interfaces (via code generation)\n* Plain functions\n* Struct methods\n\nIt is especially suitable for **unit testing** and **component testing** in microservice architectures.\n\n## Features\n\n### Type System and Language Features\n\n* **Type Safety \u0026 Generics Support**\n\n    * Native support for generic interfaces and generic functions\n    * Full type inference and auto-completion provided by IDEs\n\n* **Multiple Parameters and Multiple Return Values**\n\n    * Supports up to **7 parameters**\n    * Supports up to **4 return values**\n    * Covers the vast majority of real-world business function signatures\n\n### Mocking Modes\n\n* **Handle Mode**\n\n    * Encapsulates the entire mock logic in a single callback\n    * Suitable for scenarios with complex conditional logic\n\n* **When / Return Mode**\n\n    * Returns results based on condition matching\n    * Better suited for declarative and highly readable mock configurations\n\n### Mock Target Types\n\n* **Interface Mocking**\n\n    * Automatically generates mock implementations via code generation\n    * No reliance on `context.Context` parameter\n\n* **Plain Function \u0026 Struct Method Mocking**\n\n    * Propagates mock configuration through `context.Context`\n    * No need to introduce additional interfaces for functions or methods\n\n### Concurrency and Context\n\n* **Concurrent Testing Support**\n\n    * Passes the Mock Manager via `context.Context`\n    * Ensures isolation and safety of mocks in concurrent test scenarios\n\n## Installation\n\n### Standalone Installation\n\n```\ngo install github.com/go-spring/gs-mock@latest\n```\n\n### Installation via the gs Toolchain\n\n```\n/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/go-spring/gs/HEAD/install.sh)\"\n```\n\n## Quick Start\n\n### 1. Interface Mocking\n\n#### 1. Define an Interface\n\n```\ntype Service interface {\n    Do(n int, s string) (int, error)\n    Format(s string, args ...any) string\n}\n```\n\n#### 2. Generate Mock Code\n\n```\n//go:generate gs mock -o src_mock.go\n```\n\n\u003e `gs mock` indicates using the `mock` subcommand from the `gs` toolchain.\n\u003e You may also directly use the `gs-mock` command.\n\nAfter adding the directive at the top of the interface file, mock code will be generated for **all interfaces in the\ncurrent package**. If you only want to generate mocks for specific interfaces, use the `-i` option:\n\n```\n//go:generate gs-mock -o src_mock.go -i '!RepositoryV2,Repository'\n```\n\n**Examples of the `-i` option:**\n\n* `-i 'Repository'`\n  Generate a mock only for the `Repository` interface\n* `-i '!Repository'`\n  Generate mocks for all interfaces except `Repository`\n* `-i 'Repository,Service'`\n  Generate mocks only for `Repository` and `Service`\n* `-i '!Repository,Service'`\n  Generate mocks for all interfaces except `Repository`, but include `Service`\n\n#### 3. Using Mocks (Handle Mode)\n\n```\nr := gsmock.NewManager()\ns := NewServiceMockImpl(r)\n\n// Handle mode: determine return logic based on input arguments\ns.MockDo().Handle(func (n int, s string) (int, error) {\n    if n%2 == 0 {\n        return n * 2, nil\n    }\n    return n + 1, errors.New(\"error\")\n})\n\nfmt.Println(s.Do(1, \"abc\")) // 2 error\nfmt.Println(s.Do(2, \"abc\")) // 4 \u003cnil\u003e\n```\n\n#### 4. Using Mocks (When / Return Mode)\n\n```\nr := gsmock.NewManager()\ns := NewServiceMockImpl(r)\n\n// For args[0] == \"abc\"; variadic arguments are represented as a slice\ns.MockFormat().When(func (s string, args []any) bool {\n    return args[0] == \"abc\"\n}).ReturnValue(\"abc\")\n\n// For args[0] == \"123\"; variadic arguments are represented as a slice\ns.MockFormat().When(func (s string, args []any) bool {\n    return args[0] == \"123\"\n}).ReturnValue(\"123\")\n\nfmt.Println(s.Format(\"\", \"abc\", \"123\")) // abc\nfmt.Println(s.Format(\"\", \"123\", \"abc\")) // 123\nfmt.Println(s.Format(\"\", \"xyz\", \"abc\")) // panic: no matching mock found\n```\n\n\u003e **Notes**\n\u003e\n\u003e * Do not mix `Handle` mode and `When/Return` mode on the same method\n\u003e * When multiple `When/Return` configurations exist, they are matched in registration order; the first successful match\n    is executed\n\n### 2. Function Mocking\n\n#### 1. Define a Plain Function\n\n```\n//go:noinline // Prevent the function from being inlined\nfunc Do(ctx context.Context, n int) int { return n }\n```\n\n#### 2. Mock the Function\n\n```\nr := gsmock.NewManager()\nctx := gsmock.WithManager(context.TODO(), r)\n\n// Return a fixed value using ReturnValue\ngsmock.Func21(Do, r).ReturnValue(2)\n\nfmt.Println(Do(ctx, 1)) // 2\n```\n\n**Explanation:**\n\n* Requirements for mocking plain functions:\n\n    * The first parameter must be `context.Context`\n    * Mock configuration is propagated via the context chain\n\n* `Func21` means:\n\n    * 2 parameters\n    * 1 return value\n\n* For variadic functions, use the `VarFuncNN` series, such as `VarFunc21`\n\n### 3. Struct Method Mocking\n\n#### 1. Define a Struct Method\n\n```\ntype Service struct{ m int }\n\nfunc (s *Service) Do(ctx context.Context, n int) int {\n    return n\n}\n```\n\n#### 2. Mock the Struct Method\n\n```\nr := gsmock.NewManager()\nctx := gsmock.WithManager(context.TODO(), r)\n\n// The first parameter becomes the receiver type, followed by the original method parameters\ngsmock.Func31((*Service).Do, r).Handle(func(s *Service, ctx context.Context, n int) int {\n    return n + s.m\n})\n\nfmt.Println((\u0026Service{m: 1}).Do(ctx, 1)) // 2\nfmt.Println((\u0026Service{m: 2}).Do(ctx, 1)) // 3\n```\n\n**Notes:**\n\n* Use a **method expression** (e.g. `(*Service).Do`) instead of a method value (e.g. `s.Do`)\n* The receiver becomes the **first parameter** of the mock callback; `ctx` becomes the **second parameter**\n* Tests must be run with `-gcflags=\"all=-N -l\"` to prevent method inlining\n\n\u003e More examples and usage can be found in the [example](example) directory.\n\n## FAQ\n\n### 1. Mock Failure Due to Inlining Optimization\n\n* **Problem**:\n  In some cases, functions or methods are inlined by the Go compiler, causing mock logic not to be triggered.\n\n* **Solution**:\n  Explicitly disable compiler optimizations when running tests:\n\n  ```\n  go test -gcflags=\"all=-N -l\" ./...\n  ```\n\n* **Explanation**:\n  This disables inlining and certain optimizations, ensuring the mock framework can correctly intercept calls.\n\n### 2. Context Parameter Requirement\n\n* **Problem**:\n  When mocking plain functions or struct methods, the first parameter must be `context.Context`.\n\n* **Solution**:\n  When designing testable functions, include `context.Context` as the first parameter to allow mock manager propagation.\n\n* **Notes**:\n\n    * This restriction **only applies to plain functions and struct method mocking**\n    * **Interface mocks do not require** `context.Context` in method signatures\n\n### 3. When / Return Registration Order\n\n* **Problem**:\n  When multiple `When/Return` rules are registered for the same method, matching order affects the outcome.\n\n* **Solution**:\n  **The first successfully matched rule is executed**, so register rules from **most specific to most general**.\n\n### 4. Manager Scope and Concurrency Safety\n\n* **Problem**:\n  The `Mock Manager` itself is not goroutine-safe. Registering mocks dynamically during concurrent execution may cause\n  unpredictable behavior.\n\n* **Solution**:\n  All mock registrations must be completed **before any concurrent logic starts**, and the manager should be passed to\n  goroutines via `context.Context`.\n\n### 5. Mocking Variadic Functions\n\n* **Problem**:\n  Variadic functions (e.g. `Printf(format string, args ...any)`) have different parameter structures during mocking and\n  require special handling.\n\n* **Solution**:\n  Use the `VarFuncNN` series to mock variadic functions.\n\n* **Explanation**:\n\n    * Variadic arguments are wrapped as a single slice parameter in the mock callback\n    * All variadic mock types are prefixed with `Var`\n\n## License\n\nThis project is licensed under the Apache License Version 2.0.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgo-spring%2Fgs-mock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgo-spring%2Fgs-mock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgo-spring%2Fgs-mock/lists"}