{"id":32196911,"url":"https://github.com/metametadata/clj-fakes","last_synced_at":"2026-02-22T10:38:55.977Z","repository":{"id":57713441,"uuid":"42732591","full_name":"metametadata/clj-fakes","owner":"metametadata","description":"An isolation framework for Clojure/ClojureScript.","archived":false,"fork":false,"pushed_at":"2019-06-30T18:17:03.000Z","size":1323,"stargazers_count":30,"open_issues_count":2,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-22T02:50:14.869Z","etag":null,"topics":["assertions","fake","isolation-framework","mocking","monkey-patching","stub","tdd"],"latest_commit_sha":null,"homepage":"http://metametadata.github.io/clj-fakes/","language":"Clojure","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/metametadata.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-09-18T16:07:07.000Z","updated_at":"2024-06-24T01:58:16.000Z","dependencies_parsed_at":"2022-09-26T21:30:54.586Z","dependency_job_id":null,"html_url":"https://github.com/metametadata/clj-fakes","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/metametadata/clj-fakes","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metametadata%2Fclj-fakes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metametadata%2Fclj-fakes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metametadata%2Fclj-fakes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metametadata%2Fclj-fakes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/metametadata","download_url":"https://codeload.github.com/metametadata/clj-fakes/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metametadata%2Fclj-fakes/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29709596,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-22T10:34:24.778Z","status":"ssl_error","status_checked_at":"2026-02-22T10:32:23.200Z","response_time":110,"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":["assertions","fake","isolation-framework","mocking","monkey-patching","stub","tdd"],"created_at":"2025-10-22T02:44:46.848Z","updated_at":"2026-02-22T10:38:55.970Z","avatar_url":"https://github.com/metametadata.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"**clj-fakes** is an isolation framework for Clojure/ClojureScript that makes creating [test doubles](https://en.wikipedia.org/wiki/Test_double) much easier.\n\n[![Clojars Project](https://img.shields.io/clojars/v/clj-fakes.svg)](https://clojars.org/clj-fakes)\n[![Gitter](https://img.shields.io/gitter/room/metametadata/clj-fakes.svg?maxAge=2592000?style=plastic)](https://gitter.im/metametadata/clj-fakes)\n\n# Features\n* All test doubles are named \"fakes\" to simplify the terminology.\n* Fakes can be created for:\n    * functions\n    * instances of protocols and Java interfaces\n* \"Nice\" and \"strict\" protocol fakes are supported.\n* Monkey patching is supported to fake implicit dependencies.\n* Several functions are provided for asserting recorded calls.\n* Self-testing: automatically checks for unused fakes.\n* Informative error messages.\n* Test runner agnostic.\n* Arrange-Act-Assert style testing.\n\n# Installation\nRequirements: Clojure 1.7.0+ and/or ClojureScript 1.10.238+.\n\nAdd this to your dependencies:\n\n```clj\n[clj-fakes \"0.12.0\"]\n```\n\nRequire framework namespace in your unit test source file:\n\n```clj\n(ns unit.example\n  (:require\n    [clj-fakes.core :as f]    \n    ; and/or:\n    [clj-fakes.context :as fc]))\n```\n\n# Cheat Sheet\n\n### Creating Faking Context\n\nExplicit context:\n\n```clj\n(let [ctx (fc/context)]\n  ; use clj-fakes.context API here\n)\n```\n\nImplicit context:\n\n```clj\n(f/with-fakes\n  ; use clj-fakes.core API here \n)\n; on exit block will automatically unpatch all patched vars and execute self-tests\n```\n\nAll the following examples are assumed to be used inside an implicit context.\n\n### Stubbing\n\n#### Function Stub\n\n```clj\n(let [foo (f/fake [[1 2] \"foo\"\n                   [3 4 5] \"bar\"])]\n  (foo 1 2) ; =\u003e \"foo\"\n  (foo 3 4 5) ; =\u003e \"bar\"\n  (foo 100 200)) ; =\u003e raises \"Unexpected args are passed into fake: (100 200) ...\"\n```\n\n#### Method Stub\n\n```clj\n(let [cow (f/reify-fake p/AnimalProtocol\n                        (sleep :fake [[] \"zzz\"]))]\n  (p/sleep cow) ; =\u003e \"zzz\"\n  (p/speak cow)) ; =\u003e undefined method exception\n```\n\n#### Nice Method Stub\n\n```clj\n(let [cow (f/reify-nice-fake p/AnimalProtocol)]\n  (p/sleep cow) ; =\u003e FakeReturnValue\n  (p/speak cow)) ; =\u003e FakeReturnValue \n```\n\n### Mocking\n\n#### Function Mock\n\n```clj\n(let [foo (f/recorded-fake [[(f/arg integer?) (f/arg integer?)] #(+ %1 %2)])\n      bar (f/recorded-fake [[(f/arg integer?) (f/arg integer?)] #(* %1 %2)])]\n  (foo 1 2)\n  (bar 5 6)\n  (foo 7 8)\n       \n  (f/calls foo)\n  ; =\u003e [{:args [1 2] :return-value 3}\n  ;     {:args [7 8] :return-value 15}]\n\n  (f/calls)\n  ; =\u003e [[foo {:args [1 2] :return-value 3}]\n  ;     [bar {:args [5 6] :return-value 30}]\n  ;     [foo {:args [7 8] :return-value 15}]]\n)\n```\n\n#### Method Mock\n\n```clj\n(let [cow (f/reify-fake p/AnimalProtocol\n                        (speak :recorded-fake [f/any \"moo\"]))]\n  (p/speak cow)\n    \n  (f/calls (f/method cow p/speak))) ; =\u003e [{:args ..., :return-value moo}]\n```\n\n### Assertions\n\nThese functions return true or raise an exception and can be used only with recorded fakes.\n\n#### Strictly One Call\n\n```clj\n(f/was-called-once foo [1 2])\n\n(f/method-was-called-once p/speak cow [\"Bob\"])\n```\n\n#### At Least One Call\n\n```clj\n(f/was-called foo [1 2])\n\n(f/method-was-called p/speak cow [\"Bob\"])\n```\n\n#### Strictly One Call Matched The Provided Args Matcher\n\n```clj\n(f/was-matched-once foo [1 2])\n\n(f/method-was-matched-once p/speak cow [\"Bob\"])\n```\n\n#### No Calls\n\n```clj\n(f/was-not-called foo)\n\n(f/method-was-not-called p/speak cow)\n```\n\n#### Calls In The Specified Order\n\n```clj\n(f/were-called-in-order\n  foo [1 2 3]\n  foo [(f/arg integer?)]\n  bar [100 200]\n  baz [300])\n\n(f/methods-were-called-in-order\n  p/speak cow []\n  p/sleep cow []\n  p/eat dog [\"dog food\" \"water\"]\n  p/speak cow [\"Bob\"])\n```\n\n### Monkey Patching\n\n**Caution**: this feature is not thread-safe.\nStrongly consider avoiding it in Clojure code if you plan to someday run your tests concurrently.\n\n#### Patch Function With Stub\n\n```clj\n(f/with-fakes\n  (f/patch! #'funcs/sum (f/fake [[1 2] \"foo\"\n                                 [3 4] \"bar\"]))\n  (funcs/sum 1 2) ; =\u003e \"foo\"\n  (funcs/sum 3 4)) ; =\u003e \"bar\"\n\n; patching is reverted on exiting with-fakes block\n(funcs/sum 1 2) ; =\u003e 3\n```\n\n#### Patch To Spy\n\n```clj\n(f/patch! #'funcs/sum (f/recorded-fake [f/any funcs/sum]))\n(funcs/sum 1 2) ; =\u003e 3\n(f/was-called funcs/sum [1 2]) ; =\u003e true\n```\n\n### Self-tests\n\n```clj\n(f/with-fakes\n  (f/fake [f/any nil]))\n; =\u003e raises \"Self-test: no call detected for: non-optional fake ...\"\n\n(f/with-fakes\n  (f/recorded-fake))\n; =\u003e raises \"Self-test: no check performed on: recorded fake ...\"\n```\n\n# Documentation\nMore documentation can be found at [the project site](http://metametadata.github.io/clj-fakes/):\n\n* [Quickstart](http://metametadata.github.io/clj-fakes/quickstart/)\n* [User Guide](http://metametadata.github.io/clj-fakes/user-guide/)\n* [API Reference](http://metametadata.github.io/clj-fakes/api/)\n* [Developer Guide](http://metametadata.github.io/clj-fakes/dev-guide/)\n\n# References\nThe API was mainly inspired by [jMock](http://www.jmock.org/) and\n[unittest.mock](https://docs.python.org/3/library/unittest.mock.html) frameworks with\ndesign decisions loosely based on the\n[\"Fifteen things I look for in an Isolation framework\" by Roy Osherove](http://osherove.com/blog/2013/11/23/fifteen-things-i-look-for-in-an-isolation-framework.html).\n\nSome alternative frameworks with isolation capabilities:\n\n* [bond](https://github.com/circleci/bond)\n* [clj-mock](https://github.com/EchoTeam/clj-mock)\n* [conjure](https://github.com/amitrathore/conjure)\n* [Midje](https://github.com/marick/Midje)\n* [shrubbery](https://github.com/bguthrie/shrubbery)\n* [speclj](https://github.com/slagyr/speclj)\n* [Untangled Spec](https://github.com/untangled-web/untangled-spec)\n\nAlso take at look at the article\n[\"Isolating External Dependencies in Clojure\" by Joseph Wilk](http://blog.josephwilk.net/clojure/isolating-external-dependencies-in-clojure.html).\n\nFor more detailed information about unit testing, TDD and test double patterns I'd recommend the books below:\n\n* \"Test Driven Development: By Example\" by Kent Beck\n* \"Growing Object-Oriented Software, Guided by Tests\" by Steve Freeman and Nat Pryce [[site](http://www.growing-object-oriented-software.com/)]\n* \"xUnit Test Patterns: Refactoring Test Code\" by Gerard Meszaros [[site](http://xunitpatterns.com/)]\n\n# License\nCopyright © 2015 Yuri Govorushchenko.\n\nReleased under an MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetametadata%2Fclj-fakes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetametadata%2Fclj-fakes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetametadata%2Fclj-fakes/lists"}