{"id":13632278,"url":"https://github.com/nrxus/faux","last_synced_at":"2026-04-08T12:01:47.142Z","repository":{"id":43686550,"uuid":"202497999","full_name":"nrxus/faux","owner":"nrxus","description":"Struct mocking library for Rust","archived":false,"fork":false,"pushed_at":"2025-09-27T00:55:19.000Z","size":1766,"stargazers_count":478,"open_issues_count":13,"forks_count":19,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-12-13T23:54:01.686Z","etag":null,"topics":["mock","mocking","rust","testing"],"latest_commit_sha":null,"homepage":"https://nrxus.github.io/faux/","language":"Rust","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/nrxus.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2019-08-15T07:50:29.000Z","updated_at":"2025-12-03T03:43:20.000Z","dependencies_parsed_at":"2024-03-15T21:23:41.937Z","dependency_job_id":"b492fd20-68d6-4edc-941b-a5a56b22f1b1","html_url":"https://github.com/nrxus/faux","commit_stats":{"total_commits":170,"total_committers":7,"mean_commits":"24.285714285714285","dds":0.09999999999999998,"last_synced_commit":"709e053cc151bd8fa82578f1b28497ed26dbb1e1"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nrxus/faux","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nrxus%2Ffaux","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nrxus%2Ffaux/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nrxus%2Ffaux/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nrxus%2Ffaux/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nrxus","download_url":"https://codeload.github.com/nrxus/faux/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nrxus%2Ffaux/sbom","scorecard":{"id":696954,"data":{"date":"2025-08-11","repo":{"name":"github.com/nrxus/faux","commit":"17097585ffd10c21717a903076c2f3ae02424abe"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":1,"reason":"Found 4/22 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/pages.yml:1","Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pages.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/nrxus/faux/pages.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/pages.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/nrxus/faux/pages.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/pages.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/nrxus/faux/pages.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:9: update your workflow using https://app.stepsecurity.io/secureworkflow/nrxus/faux/test.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/nrxus/faux/test.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/nrxus/faux/test.yml/master?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   4 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 12 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-22T03:58:24.746Z","repository_id":43686550,"created_at":"2025-08-22T03:58:24.746Z","updated_at":"2025-08-22T03:58:24.746Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31554110,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T10:21:54.569Z","status":"ssl_error","status_checked_at":"2026-04-08T10:21:38.171Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":["mock","mocking","rust","testing"],"created_at":"2024-08-01T22:02:58.622Z","updated_at":"2026-04-08T12:01:45.817Z","avatar_url":"https://github.com/nrxus.png","language":"Rust","readme":"# faux \u0026emsp; [![Latest Version]][crates.io] [![rustc 1.65+]][Rust 1.65] [![docs]][api docs] ![][build]\n\nA library to create [mocks] out of structs.\n\n`faux` allows you to mock the methods of structs for testing without\ncomplicating or polluting your code.\n\nSee the [API docs] for more information.\n\n## Getting Started\n\n`faux` makes liberal use of unsafe Rust features, so it is only\nrecommended for use inside tests. To prevent `faux` from leaking into\nyour production code, set it as a `dev-dependency` in your\n`Cargo.toml`:\n\n```toml\n[dev-dependencies]\nfaux = \"^0.1\"\n```\n`faux` provides two attributes:\n* `#[create]`: transforms a struct into a mockable equivalent\n* `#[methods]`: transforms the methods in an `impl` block into their\n  mockable equivalent\n\nUse Rust's `#[cfg_attr(...)]` to gate these attributes to the test\nconfig only.\n\n```rust\n#[cfg_attr(test, faux::create)]\npub struct MyStructToMock { /* fields */ }\n\n#[cfg_attr(test, faux::methods)]\nimpl MyStructToMock { /* methods to mock */ }\n```\n\n## Examples\n\n```rust\nmod client {\n    // #[faux::create] makes a struct mockable and\n    // generates an associated `faux` function\n    // e.g., `UserClient::faux()` will create a mock `UserClient` instance\n    #[faux::create]\n    pub struct UserClient { /* data of the client */ }\n\n    #[derive(Clone)]\n    pub struct User {\n        pub name: String\n    }\n\n    // #[faux::methods] makes every public method in the `impl` block mockable\n    #[faux::methods]\n    impl UserClient {\n        pub fn fetch(\u0026self, id: usize) -\u003e User {\n            // does some network calls that we rather not do in tests\n            User { name: \"\".into() }\n        }\n    }\n}\n\nuse crate::client::UserClient;\n\npub struct Service {\n    client: UserClient,\n}\n\n#[derive(Debug, PartialEq)]\npub struct UserData {\n    pub id: usize,\n    pub name: String,\n}\n\nimpl Service {\n    fn user_data(\u0026self) -\u003e UserData {\n        let id = 3;\n        let user = self.client.fetch(id);\n        UserData { id, name: user.name }\n    }\n}\n\n// A sample #[test] for Service that mocks the client::UserClient\nfn main() {\n    // create a mock of client::UserClient using `faux`\n    let mut client = client::UserClient::faux();\n\n    // mock fetch but only if the argument is 3\n    // argument matchers are optional\n    faux::when!(client.fetch(3))\n        // stub the return value for this mock\n        .then_return(client::User { name: \"my user name\".into() });\n\n    // prepare the subject for your test using the mocked client\n    let subject = Service { client };\n\n    // assert that your subject returns the expected data\n    let expected = UserData { id: 3, name: String::from(\"my user name\") };\n    assert_eq!(subject.user_data(), expected);\n}\n```\n\n**Due to [constraints with rustdocs], the above example tests in\n`main()` rather than a `#[test]` function. In real life, the faux\nattributes should be gated to `#[cfg(test)]`.**\n\n## Features\n`faux` lets you mock the return value or implementation of:\n\n* Async methods\n* Trait methods\n* Generic struct methods\n* Methods with pointer self types (e.g., `self: Rc\u003cSelf\u003e`)\n* Methods in external modules (but not external crates).\n\n`faux` also provides easy-to-use argument matchers.\n\n## Interaction with `#[derive(...)]` and auto-traits.\n\n`faux` mocks will auto implement `Send` and `Sync` if the real\ninstance also implements it. Using `#[derive(...)]` for `Clone`,\n`Debug`, and `Default` will also work as expected. Other derivable\ntraits are not supported as they are about data (e.g., `Eq`, or\n`Hash`) but `faux` is about mocking behavior not data. Deriving traits\nthat are not part of the standard library is also not currently\nsupported. An escape hatch for this is to manually write the `impl`\nfor that trait. If you believe there is a derivable trait that `faux`\nshould support please file an issue explaining your use case.\n\n`Clone` is a bit of a special case in that it does not duplicate the\nstubs but instead shares them with the cloned instance. If this is not\nthe desired behavior for cloning mocks you may instead implement\n`Clone` manually and do normal method stubbing\n(`faux::when!(my_struct.clone()).then_return(/* something */)`). Note\nthat for the cases of exhaustable stubs (e.g.,\n`faux::when!(my_struct.foo()).once()`) if either instance calls for\nthe stub that will count as exhausting the stub as they are shared.\n\n## Interactions with other proc macros\n\nWhile `faux` makes no guarantees that it will work with other macro\nlibraries, it should \"just\" work. There are some caveats, however. For\na quick solution, try making the `faux` attributes (e.g.\n`#[faux::methods]`) the first attribute.\n\n### Explanation\n\nIf another `proc-macro` modifies the *signature* of a method before\n`faux` does its macro expansion, then it could modify the signature\ninto something not supported by `faux`. Unfortunately, [the order of\nproc macros is not specified]. However, in practice it *seems* to\nexpand top-down (tested in Rust 1.42).\n\n```rust ignore\n#[faux::create]\nstruct Foo { /*some items here */ }\n\n#[faux::methods]\n#[another_attribute]\nimpl Foo {\n    /* some methods here */\n}\n```\n\nIn the snippet above, `#[faux::methods]` will expand first followed by\n`#[another_attribute]`.`faux` is effectively ignoring the other macro\nand expanding based on the code you wrote.\n\nIf `#[faux::methods]` performs its expansion after another macro has\nmodified the `impl` block, `#[faux::methods]` receives the expanded\ncode. This code might contain different method signatures than what\nyou originally wrote. Note that the other proc macro's expansion may\ncreate code that `faux` cannot handle (e.g. explicit lifetimes).\n\nFor a concrete example, let's look at\n[`async-trait`](https://github.com/dtolnay/async-trait). `async-trait` effectively converts:\n\n```rust ignore\nasync fn run(\u0026self, arg: Arg) -\u003e Out {\n    /* stuff inside */\n}\n```\n\n```rust ignore\nfn run\u003c'async\u003e(\u0026'async self, arg: Arg) -\u003e Pin\u003cBox\u003cdyn std::future::Future\u003cOutput = Out\u003e + Send + 'async\u003e\u003e {\n    /* crazier stuff inside */\n}\n```\n\nBecause `async-trait` adds explicit lifetimes to the method signature,\nwhich `faux` cannot handle, having `async-trait` do its expansion\nfirst breaks `faux`. Note that even if `faux` could handle explicit\nlifetimes, our signature is now so unwieldy that it would make mocks\nhard to work with. Because `async-trait` just wants an `async`\nfunction signature, and `faux` does not modify function signatures, it\nis okay for `faux` to expand first.\n\n```rust ignore\n#[faux::methods]\n#[async_trait]\nimpl MyStruct for MyTrait {\n    async fn run(\u0026self, arg: Arg) -\u003e Out {\n        /* stuff inside */\n    }\n}\n```\n\nIf you find a proc macro that `faux` cannot handle, please open an\nissue to see if `faux` is doing something unexpected that conflicts\nwith that macro.\n\n## Goal\n\n`faux` was founded on the belief that traits with single\nimplementations are an undue burden and an unnecessary layer of\nabstraction. Thus, `faux` does not rely on trait definitions for every\nmocked object, which would pollute their function signatures with\neither generics or trait objects. `faux` aims to create mocks out of\nuser-defined structs, avoiding extra production code that exists\nsolely for tests.\n\n## Inspiration\n\nThis library was inspired by [mocktopus], a mocking library for\nnightly Rust that lets you mock any function. Unlike mocktopus, `faux`\nworks on stable Rust and deliberately only allows for mocking public\nmethods in structs.\n\n[Latest Version]: https://img.shields.io/crates/v/faux.svg\n[crates.io]: https://crates.io/crates/faux\n[rustc 1.65+]: https://img.shields.io/badge/rustc-1.65+-blue.svg\n[Rust 1.65]: https://blog.rust-lang.org/2022/11/03/Rust-1.65.0/\n[Latest Version]: https://img.shields.io/crates/v/faux.svg\n[docs]: https://img.shields.io/badge/api-docs-blue.svg\n[api docs]: https://docs.rs/faux/\n[mocktopus]: https://github.com/CodeSandwich/Mocktopus\n[build]: https://github.com/nrxus/faux/workflows/test/badge.svg\n[constraints with rustdocs]: https://github.com/rust-lang/rust/issues/45599\n[the order of proc macros is not specified]: https://github.com/rust-lang/reference/issues/578\n[mocks]: https://martinfowler.com/articles/mocksArentStubs.html\n","funding_links":[],"categories":["Rust","Crates","Development tools"],"sub_categories":["Mocking","Testing"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnrxus%2Ffaux","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnrxus%2Ffaux","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnrxus%2Ffaux/lists"}