{"id":16819590,"url":"https://github.com/slowli/mimicry","last_synced_at":"2025-03-17T14:48:40.941Z","repository":{"id":41227056,"uuid":"508787119","full_name":"slowli/mimicry","owner":"slowli","description":"Lightweight mocking / spying library for Rust","archived":false,"fork":false,"pushed_at":"2022-12-30T16:20:54.000Z","size":1232,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-31T01:46:14.766Z","etag":null,"topics":["mocking-library","spying"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/slowli.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-06-29T17:31:51.000Z","updated_at":"2022-06-29T18:03:12.000Z","dependencies_parsed_at":"2023-01-31T12:02:02.021Z","dependency_job_id":null,"html_url":"https://github.com/slowli/mimicry","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slowli%2Fmimicry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slowli%2Fmimicry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slowli%2Fmimicry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slowli%2Fmimicry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/slowli","download_url":"https://codeload.github.com/slowli/mimicry/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244055249,"owners_count":20390712,"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":["mocking-library","spying"],"created_at":"2024-10-13T10:53:58.309Z","updated_at":"2025-03-17T14:48:40.904Z","avatar_url":"https://github.com/slowli.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lightweight Mocking / Spying Library for Rust\n\n[![Build Status](https://github.com/slowli/mimicry/workflows/CI/badge.svg?branch=main)](https://github.com/slowli/mimicry/actions)\n[![License: MIT OR Apache-2.0](https://img.shields.io/badge/License-MIT%2FApache--2.0-blue)](https://github.com/slowli/mimicry#license)\n![rust 1.59+ required](https://img.shields.io/badge/rust-1.59+-blue.svg?label=Required%20Rust)\n\n**Documentation:** [![Docs.rs](https://docs.rs/mimicry/badge.svg)](https://docs.rs/mimicry/)\n[![crate docs (main)](https://img.shields.io/badge/main-yellow.svg?label=docs)](https://slowli.github.io/mimicry/mimicry/)\n\nMocking in Rust is somewhat hard compared to object-oriented languages. Since there\nis no implicit / all-encompassing class hierarchy, [Liskov substitution principle]\ndoes not apply, thus making it generally impossible to replace an object with its mock.\nA switch is only possible if the object consumer explicitly opts in via\nparametric polymorphism or dynamic dispatch.\n\nWhat do? Instead of trying to emulate mocking approaches from the object-oriented world,\nthis crate opts in for another approach, somewhat similar to [remote derive] from `serde`.\nMocking is performed on function / method level, with each function conditionally proxied\nto a mock that has access to function args and can do whatever: call the \"real\" function\n(e.g., to spy on responses), maybe with different args and/or after mutating args;\nsubstitute with a mock response, etc. Naturally, mock logic\ncan be stateful (e.g., determine a response from the predefined list; record responses\nfor spied functions etc.)\n\n## Usage\n\nAdd this to your `Crate.toml`:\n\n```toml\n[dev-dependencies]\nmimicry = \"0.1.0\"\n```\n\nExample of usage:\n\n```rust\nuse mimicry::{mock, CallReal, Mock, Mut};\n\n// Tested function\n#[mock(using = \"SearchMock\")]\nfn search(haystack: \u0026str, needle: char) -\u003e Option\u003cusize\u003e {\n    haystack.chars().position(|ch| ch == needle)\n}\n\n// Mock logic\n#[derive(Default, Mock)]\n#[mock(mut)]\n// ^ Indicates that the mock state is wrapped in a wrapper with \n// internal mutability.\nstruct SearchMock {\n    called_times: usize,\n}\n\nimpl SearchMock {\n    // Implementation of mocked function, which the mocked function\n    // will delegate to if the mock is set.\n    fn search(\n        this: \u0026Mut\u003cSelf\u003e,\n        haystack: \u0026str,\n        needle: char,\n    ) -\u003e Option\u003cusize\u003e {\n        this.borrow().called_times += 1;\n        if haystack == \"test\" {\n            Some(42)\n        } else {\n            let new_needle = if needle == '?' { 'e' } else { needle };\n            this.call_real().scope(|| search(haystack, new_needle))\n        }\n    }\n}\n\n// Test code.\nlet guard = SearchMock::default().set_as_mock();\nassert_eq!(search(\"test\", '?'), Some(42));\nassert_eq!(search(\"needle?\", '?'), Some(1));\nassert_eq!(search(\"needle?\", 'd'), Some(3));\nlet recovered = guard.into_inner();\nassert_eq!(recovered.called_times, 3);\n```\n\nSee crate docs for more details and examples of usage.\n\n## Features\n\n- Can mock functions / methods with a wide variety of signatures, including generic functions\n  (with not necessarily `'static` type params), functions returning non-`'static` responses\n  and responses with dependent lifetimes, such as in `fn(\u0026str) -\u003e \u0026str`, functions with\n  `impl Trait` args etc.\n- Can mock methods in `impl` blocks, including trait implementations.\n- Single mocking function can mock multiple functions, provided that they have compatible\n  signatures.\n- Whether mock state is shared across functions / methods, is completely up to the test writer.\n  Functions for the same receiver type / in the same `impl` block may have different\n  mock states.\n- Mocking functions can have wider argument types than required from the signature of\n  function(s) being mocked. For example, if the mocking function doesn't use some args,\n  they can be just replaced with unconstrained type params.\n\n### Downsides\n\n- You still cannot mock types from other crates.\n- Even if mocking logic does not use certain args, they need to be properly constructed,\n  which, depending on the case, may defy the reasons behind using mocks.\n- Very limited built-in matching / verifying. With the chosen approach,\n  it is frequently easier and more transparent to just use `match` statements.\n  As a downside, if matching logic needs to be customized across tests, it's (mostly)\n  up to the test writer.\n\n## Alternatives\n\n[`mockall`], [`simulacrum`], [`mocktopus`], [`mockiato`] etc. provide more traditional approach\nto mocking based on configuring expectations for called functions / methods.\n\n## License\n\nLicensed under either of [Apache License, Version 2.0](LICENSE-APACHE)\nor [MIT license](LICENSE-MIT) at your option.\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in `mimicry` by you, as defined in the Apache-2.0 license,\nshall be dual licensed as above, without any additional terms or conditions.\n\n[Liskov substitution principle]: https://en.wikipedia.org/wiki/Liskov_substitution_principle\n[remote derive]: https://serde.rs/remote-derive.html\n[`mockall`]: https://crates.io/crates/mockall\n[`simulacrum`]: https://crates.io/crates/simulacrum\n[`mocktopus`]: https://crates.io/crates/mocktopus\n[`mockiato`]: https://crates.io/crates/mockiato\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslowli%2Fmimicry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslowli%2Fmimicry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslowli%2Fmimicry/lists"}