{"id":13827346,"url":"https://github.com/gcapizzi/moka","last_synced_at":"2026-01-30T16:17:27.210Z","repository":{"id":140820868,"uuid":"104407422","full_name":"gcapizzi/moka","owner":"gcapizzi","description":"A Go mocking framework.","archived":false,"fork":false,"pushed_at":"2025-07-30T20:12:11.000Z","size":91,"stargazers_count":50,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-30T22:52:48.996Z","etag":null,"topics":["go","golang","mock","mocking","tdd","test-doubles","test-driven-development","testing"],"latest_commit_sha":null,"homepage":"","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/gcapizzi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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}},"created_at":"2017-09-21T23:09:42.000Z","updated_at":"2025-07-30T20:12:15.000Z","dependencies_parsed_at":"2024-01-15T16:24:04.677Z","dependency_job_id":"0d8d1483-a587-44be-9acf-7cfc408e69ce","html_url":"https://github.com/gcapizzi/moka","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gcapizzi/moka","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gcapizzi%2Fmoka","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gcapizzi%2Fmoka/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gcapizzi%2Fmoka/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gcapizzi%2Fmoka/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gcapizzi","download_url":"https://codeload.github.com/gcapizzi/moka/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gcapizzi%2Fmoka/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28915115,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T12:13:43.263Z","status":"ssl_error","status_checked_at":"2026-01-30T12:13:22.389Z","response_time":66,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["go","golang","mock","mocking","tdd","test-doubles","test-driven-development","testing"],"created_at":"2024-08-04T09:01:54.429Z","updated_at":"2026-01-30T16:17:27.179Z","avatar_url":"https://github.com/gcapizzi.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/gcapizzi/moka/master/images/logo.png\" /\u003e\n  \u003cbr /\u003e\n  Moka\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eA Go mocking framework.\u003c/strong\u003e\n  \u003cbr /\u003e\n  \u003ca href=\"https://godoc.org/github.com/gcapizzi/moka\"\u003e\n    \u003cimg alt=\"GoDOc\" src=\"https://godoc.org/github.com/gcapizzi/moka?status.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://travis-ci.org/gcapizzi/moka\"\u003e\n    \u003cimg alt=\"TravisCI\" src=\"https://travis-ci.org/gcapizzi/moka.svg?branch=master\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://goreportcard.com/report/github.com/gcapizzi/moka\"\u003e\n    \u003cimg alt=\"Go Report Card\" src=\"https://goreportcard.com/badge/github.com/gcapizzi/moka\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cstrong\u003eMoka\u003c/strong\u003e is a mocking framework for the [Go programming\nlanguage](https://golang.org). Moka works very well with the [Ginkgo testing\nframework](http://onsi.github.io/ginkgo), but can be easily used with any other\ntesting framework, including the `testing` package from the standard library.\n\n## Getting Moka\n\n```\ngo get github.com/gcapizzi/moka\n```\n\n## Setting Up Moka\n\n### Ginkgo\n\nMoka is designed to play well with [Ginkgo](http://onsi.github.io/ginkgo). All\nyou'll need to do is:\n\n* import the `moka` package;\n* register Ginkgo's `Fail` function as Moka's double fail handler using\n  `RegisterDoublesFailHandler`.\n\nHere's an example:\n\n```go\npackage game_test\n\nimport (\n\t. \"github.com/gcapizzi/moka\"\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n\n\t\"testing\"\n)\n\nfunc TestGame(t *testing.T) {\n\tRegisterFailHandler(Fail)\n\tRegisterDoublesFailHandler(Fail)\n\tRunSpecs(t, \"Game Suite\")\n}\n```\n\n### `testing` and other frameworks\n\nSupport for the [`testing`](https://golang.org/pkg/testing) package hasn't been\nadded yet, but this doesn't mean you can't use Moka with it.\n\nHere is the type for the Moka doubles fail handler:\n\n```go\ntype FailHandler func(message string, callerSkip ...int)\n```\n\nThis type is modelled to match Ginkgo's `Fail` function. To use Moka with the\n`testing` package, just provide a doubles fail handler that makes the test\nfail!\n\nHere's an example:\n\n```go\npackage game\n\nimport (\n\t. \"github.com/gcapizzi/moka\"\n\n\t\"testing\"\n)\n\nfunc TestGame(t *testing.T) {\n\tRegisterDoublesFailHandler(func(message string, callerSkip ...int) {\n\t\tt.Fatal(message)\n\t})\n\n\t// use Moka here\n}\n```\n\n## Getting Started: Building Your First Double\n\nA test double is an object that stands in for another object in your system\nduring tests. The first step to use Moka is to declare a double type. The type\nwill have to:\n\n* implement the same interface as the replaced object: this means that only\n  objects used through interfaces can be replaced by Moka doubles;\n* embed the `moka.Double` type;\n* delegate any method that you'll need to stub/mock to the embedded\n  `moka.Double` instance, using the `Call` method.\n\nLet's build a double type for a `Die` interface:\n\n```go\npackage dice\n\nimport (\n\t. \"github.com/gcapizzi/moka\"\n)\n\ntype Die interface {\n\tRoll(times int) []int\n}\n\ntype DieDouble struct {\n\tDouble\n}\n\nfunc NewDieDouble() DieDouble {\n\treturn DieDouble{Double: NewStrictDouble()}\n}\n\nfunc (d DieDouble) Roll(times int) []int {\n\treturnValues, _ := d.Call(\"Roll\", times)\n\treturnedRolls, _ := returnValues[0].([]int)\n\treturn returnedRolls\n}\n```\n\nSome notes:\n\n* The `Double` instance we are embedding is of type `StrictDouble`: strict\n  doubles will fail the test if they receive a call on a method that wasn't\n  previously allowed or expected.\n* If the `Call` invocation fails, it will both return an error as its second\n  return value, and invoke the fail handler. Since we know the fail handler\n  will immediately stop the execution of the test, we don't need to check for\n  the error.\n* This style of type assertions allow us to have `nil` return values.\n\n## Allowing interactions\n\nNow that our double type is ready, let's use it in our tests! We will test a\n`Game` type, which looks like this:\n\n```go\npackage game\n\ntype Game struct {\n\tdie Die\n}\n\nfunc NewGame(die Die) Game {\n\treturn Game{die: die}\n}\n\nfunc (g Game) Score() int {\n\trolls := g.die.Roll(3)\n\treturn rolls[0] + rolls[1] + rolls[2]\n}\n```\n\nHere is the test:\n\n```go\npackage game_test\n\nimport (\n\t. \"github.com/gcapizzi/moka/examples/game\"\n\n\t. \"github.com/gcapizzi/moka\"\n\t. \"github.com/onsi/ginkgo\"\n\t. \"github.com/onsi/gomega\"\n)\n\nvar _ = Describe(\"Game\", func() {\n\tvar die DieDouble\n\tvar game Game\n\n\tBeforeEach(func() {\n\t\tdie = NewDieDouble()\n\t\tgame = NewGame(die)\n\t})\n\n\tDescribe(\"Score\", func() {\n\t\tIt(\"returns the sum of three die rolls\", func() {\n\t\t\tAllowDouble(die).To(ReceiveCallTo(\"Roll\").With(3).AndReturn([]int{1, 2, 3}))\n\n\t\t\tExpect(game.Score()).To(Equal(6))\n\t\t})\n\t})\n})\n```\n\n## Typed doubles\n\nYou might be wondering: what happens if I allow a method call that would be\nimpossible to perform, given the type of my double? Let's say we forgot how the\n`Die` interface was defined, and wrote a test like this:\n\n```go\nDescribe(\"Score\", func() {\n\tIt(\"returns the sum of three die rolls\", func() {\n\t\tAllowDouble(die).To(ReceiveCallTo(\"Cast\").With(3).AndReturn([]int{1, 2, 3}))\n\n\t\tExpect(game.Score()).To(Equal(9))\n\t})\n})\n```\n\nThe `Die` interface has no method called `Cast`, so our configured interaction\nwill never happen!\n\nTo avoid this kind of problems, Moka provides _typed\ndoubles_, which are associated with a type and will make sure that any\nconfigured interaction actually matches the type.\n\nTo instantiate a typed double, use the `NewStrictDoubleWithTypeOf` constructor:\n\n```go\nfunc NewDieDouble() DieDouble {\n\treturn DieDouble{Double: NewStrictDoubleWithTypeOf(DieDouble{})}\n}\n```\n\nIf run against a typed double, the previous test would fail with a message like this:\n\n```\nInvalid interaction: type 'DieDouble' has no method 'Cast'\n```\n\n## Expecting interactions\n\nSometimes allowing a method call is not enough. Some methods have side effects,\nand we need to make sure they have been invoked in order to be confident that\nour code is working.\n\nFor example, let's assume we added a `Logger` collaborator to our `Game` type:\n\n```go\npackage game\n\nimport \"fmt\"\n\ntype Logger interface {\n\tLog(message string)\n}\n\ntype StdoutLogger struct{}\n\nfunc (l StdoutLogger) Log(message string) {\n\tfmt.Println(message)\n}\n```\n\nWe'll start, as usual, by building our double type:\n\n```go\ntype LoggerDouble struct {\n\tDouble\n}\n\nfunc NewLoggerDouble() LoggerDouble {\n\treturn LoggerDouble{Double: NewStrictDoubleWithTypeOf(LoggerDouble{})}\n}\n\nfunc (d LoggerDouble) Log(message string) {\n\td.Call(\"Log\", message)\n}\n```\n\nWe can now add the `Logger` collaborator to `Game`, and test their interaction:\n\n```go\nDescribe(\"Score\", func() {\n\tIt(\"returns the sum of three die rolls\", func() {\n\t\tAllowDouble(die).To(ReceiveCallTo(\"Roll\").With(3).AndReturn([]int{1, 2, 3}))\n\t\tExpectDouble(logger).To(ReceiveCallTo(\"Log\").With(\"[1, 2, 3]\"))\n\n\t\tExpect(game.Score()).To(Equal(6))\n\n\t\tVerifyCalls(logger)\n\t})\n})\n```\n\nWe use `ExpectDouble` to expect method calls on a double, and `VerifyCalls`\nto verify that the calls have actually been made.\n\n## Custom interaction behaviour\n\nIf you need to specify a custom behaviour for your double interactions, of need\nto perform assertions on the arguments, you can specify a body for the\ninteraction using `AndDo`:\n\n```go\nDescribe(\"Score\", func() {\n\tIt(\"returns the sum of three die rolls\", func() {\n\t\tAllowDouble(die).To(ReceiveCallTo(\"Roll\").AndDo(func(times int) []int {\n\t\t\tExpect(times).To(BeNumerically(\"\u003e\", 0))\n\n\t\t\trolls := []int{}\n\t\t\tfor i := 0; i \u003c times; i++ {\n\t\t\t\trolls = append(rolls, i+1)\n\t\t\t}\n\t\t\treturn rolls\n\t\t}))\n\n\t\tExpect(game.Score()).To(Equal(6))\n\t})\n})\n```\n\n## How does Moka compare to the other Go mocking frameworks?\n\nThere are a lot of mocking libraries for Go out there, so why build a new one?\nCompared to those libraries, Moka offers:\n\n* A very readable syntax, inspired by RSpec.\n* A model that naturally supports stubbing or mocking different method calls\n  with different arguments and return values, without the need to enforce any\n  order, which would add unnecessary coupling between your tests and your\n  implementation.\n* A relatively straightforward way to declare double types, without the need for\n  a generator. We still plan to introduce a generator to make things even\n  easier.\n* Strict doubles that will make your test fail on any unexpected interaction,\n  instead of loose doubles that will return zero values and lead to confusing\n  failures.\n\nOn the other hand, Moka currently lacks:\n\n* Compile-time type safety: in order to offer such a flexible and readable\n  syntax, Moka cannot use the Go type system to detect invalid stub/mock\n  declarations at compile-time. When using typed doubles, Moka will instead\n  detect those errors at runtime and fail the test.\n* Support for argument matchers: will be implemented soon.\n* Support for enforced order of interactions: will be implemented soon.\n\n## Gotchas\n\n### Variadic Methods\n\nMoka treats variadic arguments are regular slice arguments. This means that:\n\n* You should not unpack (as in `SomeFunction(args...)`) the slice containing\n  the variadic values when passing it to `Call`.\n* You should use slices in place of variadic arguments when allowing or\n  expecting method calls.\n\nFor example, given a `Calculator` interface:\n\n```go\ntype Calculator interface {\n\tAdd(numbers ...int) int\n}\n```\n\nThis is how you should delegate `Add` to `Call` in the double implementation:\n\n```go\nfunc (d CalculatorDouble) Add(numbers ...int) int {\n\treturnValues, _ := d.Call(\"Add\", numbers)\n\n\t// ...\n}\n```\n\nAnd this is how you should allow a call to `Add`:\n\n```go\nAllowDouble(calculator).To(ReceiveCallTo(\"Add\").With([]int{1, 2, 3}).AndReturn(6))\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgcapizzi%2Fmoka","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgcapizzi%2Fmoka","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgcapizzi%2Fmoka/lists"}