{"id":13509217,"url":"https://github.com/eproxus/meck","last_synced_at":"2025-05-14T05:10:34.030Z","repository":{"id":892923,"uuid":"644426","full_name":"eproxus/meck","owner":"eproxus","description":"A mocking library for Erlang","archived":false,"fork":false,"pushed_at":"2024-12-28T17:06:47.000Z","size":2393,"stargazers_count":818,"open_issues_count":12,"forks_count":230,"subscribers_count":30,"default_branch":"master","last_synced_at":"2025-05-03T07:56:30.209Z","etag":null,"topics":["erlang","meck","mocking-library","testing"],"latest_commit_sha":null,"homepage":"http://eproxus.github.io/meck","language":"Erlang","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/eproxus.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","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},"funding":{"github":["eproxus"],"liberapay":"eproxus"}},"created_at":"2010-05-03T13:53:51.000Z","updated_at":"2025-04-09T09:08:13.000Z","dependencies_parsed_at":"2023-07-06T13:31:17.981Z","dependency_job_id":"117242c9-7392-40b5-a07a-fe44c8f5a17a","html_url":"https://github.com/eproxus/meck","commit_stats":{"total_commits":483,"total_committers":76,"mean_commits":6.355263157894737,"dds":0.6066252587991718,"last_synced_commit":"dfb47c544bdf14b5c26ff2651cf9339dbbe2f50e"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eproxus%2Fmeck","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eproxus%2Fmeck/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eproxus%2Fmeck/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eproxus%2Fmeck/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eproxus","download_url":"https://codeload.github.com/eproxus/meck/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254076849,"owners_count":22010611,"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":["erlang","meck","mocking-library","testing"],"created_at":"2024-08-01T02:01:04.691Z","updated_at":"2025-05-14T05:10:34.010Z","avatar_url":"https://github.com/eproxus.png","language":"Erlang","funding_links":["https://github.com/sponsors/eproxus","https://liberapay.com/eproxus","https://liberapay.com/eproxus/donate","https://liberapay.com/eproxus/"],"categories":["Testing","Erlang"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eMeck\u003c/h1\u003e\n\u003cp align=\"center\"\u003eA mocking library for Erlang\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/eproxus/meck/actions/workflows/erlang.yml\"\u003e\n    \u003cimg alt=\"GitHub Actions\" src=\"https://img.shields.io/github/actions/workflow/status/eproxus/meck/erlang.yml?branch=master\u0026style=flat-square\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://hex.pm/packages/meck\"\u003e\n    \u003cimg alt=\"Hex.pm version\" src=\"https://img.shields.io/hexpm/v/meck?style=flat-square\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\n    \u003cimg alt=\"Hex.pm license\" src=\"https://img.shields.io/hexpm/l/meck?style=flat-square\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/eproxus/meck/blob/master/.github/workflows/erlang.yml#L14\"\u003e\n    \u003cimg alt=\"Erlang versions\" src=\"https://img.shields.io/badge/erlang-24+-blue.svg?style=flat-square\"/\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/sponsors/eproxus\"\u003e\n    \u003cimg alt=\"hex.pm license\" src=\"https://img.shields.io/github/sponsors/eproxus?style=flat-square\u0026color=%23ec6cb9\"/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\n  * [Features](#features)\n  * [Examples](#examples)\n  * [Use](#use)\n  * [Manual Build](#manual-build)\n  * [Caveats](#caveats)\n  * [Contribute](#contribute)\n\n## Features\n\nSee what's new in [0.8 Release Notes][release_notes_0.8].\n\n  * Dynamic return values using sequences and loops of static values\n  * Compact definition of mock arguments, clauses and return values\n  * Pass through: call functions in the original module\n  * Complete call history showing calls, return values and exceptions\n  * Mock validation, will invalidate mocks that were not called correctly\n  * Throwing of expected exceptions that keeps the module valid\n  * Throws an error when mocking a module that doesn't exist or has been\n    renamed (disable with option `non_strict`)\n  * Support for [Hamcrest][hamcrest] matchers\n  * Automatic backup and restore of cover data\n  * Mock is linked to the creating process and will unload automatically\n    when a crash occurs (disable with option `no_link`)\n  * Mocking of sticky modules (using the option `unstick`)\n\n## Examples\n\nHere's an example of using Meck in the Erlang shell:\n\n```erlang\nEshell V5.8.4  (abort with ^G)\n1\u003e meck:new(dog, [non_strict]). % non_strict is used to create modules that don't exist\nok\n2\u003e meck:expect(dog, bark, fun() -\u003e \"Woof!\" end).\nok\n3\u003e dog:bark().\n\"Woof!\"\n4\u003e meck:validate(dog).\ntrue\n5\u003e meck:unload(dog).\nok\n6\u003e dog:bark().\n** exception error: undefined function dog:bark/0\n```\n\nExceptions can be anticipated by Meck (resulting in validation still passing).\nThis is intended to be used to test code that can and should handle certain\nexceptions indeed does take care of them:\n\n```erlang\n5\u003e meck:expect(dog, meow, fun() -\u003e meck:exception(error, not_a_cat) end).\nok\n6\u003e catch dog:meow().\n{'EXIT',{not_a_cat,[{meck,exception,2},\n                    {meck,exec,4},\n                    {dog,meow,[]},\n                    {erl_eval,do_apply,5},\n                    {erl_eval,expr,5},\n                    {shell,exprs,6},\n                    {shell,eval_exprs,6},\n                    {shell,eval_loop,3}]}}\n7\u003e meck:validate(dog).\ntrue\n```\n\nNormal Erlang exceptions result in a failed validation. The following example is\njust to demonstrate the behavior, in real test code the exception would normally\ncome from the code under test (which should, if not expected, invalidate the\nmocked module):\n\n```erlang\n8\u003e meck:expect(dog, jump, fun(Height) when Height \u003e 3 -\u003e\n                                  erlang:error(too_high);\n                             (Height) -\u003e\n                                  ok\n                          end).\nok\n9\u003e dog:jump(2).\nok\n10\u003e catch dog:jump(5).\n{'EXIT',{too_high,[{meck,exec,4},\n                   {dog,jump,[5]},\n                   {erl_eval,do_apply,5},\n                   {erl_eval,expr,5},\n                   {shell,exprs,6},\n                   {shell,eval_exprs,6},\n                   {shell,eval_loop,3}]}}\n11\u003e meck:validate(dog).\nfalse\n```\n\nHere's an example of using Meck inside an EUnit test case:\n\n```erlang\nmy_test() -\u003e\n    meck:new(my_library_module),\n    meck:expect(my_library_module, fib, fun(8) -\u003e 21 end),\n    ?assertEqual(21, code_under_test:run(fib, 8)), % Uses my_library_module\n    ?assert(meck:validate(my_library_module)),\n    meck:unload(my_library_module).\n```\n\nPass-through is used when the original functionality of a module should be kept.\nWhen the option `passthrough` is used when calling `new/2` all functions in the\noriginal module will be kept in the mock. These can later be overridden by\ncalling `expect/3` or `expect/4`.\n\n```erlang\nEshell V5.8.4  (abort with ^G)\n1\u003e meck:new(string, [unstick, passthrough]).\nok\n2\u003e string:strip(\"  test  \").\n\"test\"\n```\n\nIt's also possible to pass calls to the original function allowing us to\noverride only a certain behavior of a function (this usage is compatible with\nthe `passthrough` option). `passthrough/1` will always call the original\nfunction with the same name as the expect is defined in):\n\n```erlang\nEshell V5.8.4  (abort with ^G)\n1\u003e meck:new(string, [unstick, passthrough]).\nok\n2\u003e meck:expect(string, strip, fun\n    (\"foo\") -\u003e \"bar\";\n    (String) -\u003e meck:passthrough([String])\nend).\nok\n3\u003e string:strip(\"  test  \").\n\"test\"\n4\u003e string:strip(\"foo\").\n\"bar\"\n5\u003e meck:unload(string).\nok\n5\u003e string:strip(\"foo\").\n\"foo\"\n```\n\n## Use\n\nMeck is best used via [Rebar 3][rebar_3]. Add Meck to the test dependencies\nin your `rebar.config`:\n\n```erlang\n{profiles, [{test, [{deps, [meck]}]}]}.\n```\n\n### Manual Build\n\nMeck uses [Rebar 3][rebar_3]. To build Meck go to the Meck directory\nand simply type:\n\n```sh\nrebar3 compile\n```\n\nIn order to run all tests for Meck type the following command from the same\ndirectory:\n\n```sh\nrebar3 eunit\n```\n\nDocumentation can be generated through the use of the following command:\n\n```sh\nrebar3 edoc\n```\n\n### Test Output\n\nNormally the test output is hidden, but if EUnit is run\ndirectly, two things might seem alarming when running the tests:\n\n  1. Warnings emitted by cover\n  2. An exception printed by SASL\n\nBoth are expected due to the way Erlang currently prints errors. The important\nline you should look for is `All XX tests passed`, if that appears all is\ncorrect.\n\n## Caveats\n\n### Global Namespace\n\nMeck will have trouble mocking certain modules since it works by recompiling\nand reloading modules in the global Erlang module namespace. Replacing a\nmodule affects the whole Erlang VM and any running processes using that\nmodule. This means certain modules cannot be mocked or will cause trouble.\n\nIn general, if a module is used by running processes or include Native\nImplemented Functions (NIFs) they will be hard or impossible to mock. You may\nbe lucky and it could work, until it breaks one day.\n\nThe following is a non-exhaustive\nlist of modules that can either be problematic to mock or not possible at\nall:\n\n* `erlang`\n* `supervisor`\n* All `gen_` family of modules (`gen_server`, `gen_statem` etc.)\n* `os`\n* `crypto`\n* `compile`\n* `global`\n* `timer` (possible to mock, but used by some test frameworks, like Elixir's\n  ExUnit)\n\n### Local Functions\n\nA meck expectation set up for a function _f_ does not apply to the module-\nlocal invocation of _f_ within the mocked module. Consider the following module:\n\n```erlang\n-module(test).\n-export([a/0, b/0, c/0]).\n\na() -\u003e\n  c().\n\nb() -\u003e\n  ?MODULE:c().\n\nc() -\u003e\n  original.\n```\n\nNote how the module-local call to `c/0` in `a/0` stays unchanged even though the\nexpectation changes the externally visible behaviour of `c/0`:\n\n```erlang\n3\u003e meck:new(test, [passthrough]).\nok\n4\u003e meck:expect(test,c,0,changed).\nok\n5\u003e test:a().\noriginal\n6\u003e test:b().\nchanged\n6\u003e test:c().\nchanged\n```\n\n### Common Test\n\nWhen using `meck` under Erlang/OTP's Common Test, one should pay special\nattention to this bit in the chapter on\n[Writing Tests](https://erlang.org/doc/apps/common_test/write_test_chapter.html):\n\n\u003e `init_per_suite` and `end_per_suite` execute on dedicated Erlang processes,\n\u003e just like the test cases do.\n\nCommon Test runs `init_per_suite` in an isolated process which terminates when\ndone, before the test case runs. A mock that is created there will also\nterminate and unload itself before the test case runs. This is because it is\nlinked to the process creating it. This can be especially tricky to detect if\n`passthrough` is used when creating the mock, since it is hard to know if it is\nthe mock responding to function calls or the original module.\n\nTo avoid this, you can pass the `no_link` flag to `meck:new/2` which will unlink\nthe mock from the process that created it. When using `no_link` you should make\nsure that `meck:unload/1` is called properly (for all test outcomes, or\ncrashes) so that a left-over mock does not interfere with subsequent test\ncases.\n\n## Contribute\n\nPatches are greatly appreciated! For a much nicer history, please [write good\ncommit messages][commit_messages]. Use a branch name prefixed by `feature/`\n(e.g. `feature/my_example_branch`) for easier integration when developing new\nfeatures or fixes for meck.\n\nShould you find yourself using Meck and have issues, comments or feedback please\n[create an issue here on GitHub][issues].\n\nMeck has been greatly improved by [many contributors](https://github.com/eproxus/meck/graphs/contributors)!\n\n### Donations\n\nIf you or your company use Meck and find it useful, a [sponsorship][sponsors] or [donations][liberapay] are greatly appreciated!\n\n\u003cnoscript\u003e\n  \u003cspan\u003e\n   \u003ca href=\"https://github.com/sponsors/eproxus\"\u003e\n   \u003cimg alt=\"Sponsor on GitHub\"\n        src=\"https://img.shields.io/github/sponsors/eproxus?label=Sponsor\u0026color=EA4AAA\u0026logo=GitHub%20Sponsors\u0026style=social\"\u003e\n   \u003c/a\u003e\n  \u003c/span\u003e\n  \u003cspan\u003e\n    \u003ca href=\"https://liberapay.com/eproxus/donate\"\u003e\n      \u003cimg alt=\"Donate using Liberapay\"\n           src=\"https://liberapay.com/assets/widgets/donate.svg\"\u003e\n    \u003c/a\u003e\n  \u003c/span\u003e\n\u003c/noscript\u003e\n\n\u003c!-- Links --\u003e\n[release_notes_0.8]: https://github.com/eproxus/meck/wiki/0.8-Release-Notes\n[hamcrest]: https://github.com/hyperthunk/hamcrest-erlang\n[rebar_3]: https://github.com/erlang/rebar3\n[issues]: http://github.com/eproxus/meck/issues\n[commit_messages]: http://chris.beams.io/posts/git-commit/\n[sponsors]: https://github.com/sponsors/eproxus\n[liberapay]: https://liberapay.com/eproxus/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feproxus%2Fmeck","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feproxus%2Fmeck","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feproxus%2Fmeck/lists"}