{"id":33939519,"url":"https://github.com/mindsbackyard/galvanic-test","last_synced_at":"2025-12-12T15:33:23.474Z","repository":{"id":57632907,"uuid":"83033483","full_name":"mindsbackyard/galvanic-test","owner":"mindsbackyard","description":"A test environment for rust: test cases \u0026 suites, fixtures, and parameterised test cases","archived":false,"fork":false,"pushed_at":"2018-12-22T12:41:19.000Z","size":39,"stargazers_count":53,"open_issues_count":6,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-10-22T00:33:07.482Z","etag":null,"topics":["parameterised-tests","rust","test-fixtures","unit-testing"],"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/mindsbackyard.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}},"created_at":"2017-02-24T11:11:05.000Z","updated_at":"2025-08-28T03:34:15.000Z","dependencies_parsed_at":"2022-08-31T16:31:48.249Z","dependency_job_id":null,"html_url":"https://github.com/mindsbackyard/galvanic-test","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/mindsbackyard/galvanic-test","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mindsbackyard%2Fgalvanic-test","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mindsbackyard%2Fgalvanic-test/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mindsbackyard%2Fgalvanic-test/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mindsbackyard%2Fgalvanic-test/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mindsbackyard","download_url":"https://codeload.github.com/mindsbackyard/galvanic-test/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mindsbackyard%2Fgalvanic-test/sbom","scorecard":{"id":647872,"data":{"date":"2025-08-11","repo":{"name":"github.com/mindsbackyard/galvanic-test","commit":"07d645a5f4b7145b170b49a1fe53252208c1ab20"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.2,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"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":"Dangerous-Workflow","score":-1,"reason":"no workflows found","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":"Code-Review","score":1,"reason":"Found 3/26 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":"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":-1,"reason":"no dependencies found","details":null,"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":"Maintained","score":0,"reason":"0 commit(s) and 0 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":"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":"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":"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":"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":"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: Apache License 2.0: 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":"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":"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 7 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-21T12:38:22.558Z","repository_id":57632907,"created_at":"2025-08-21T12:38:22.558Z","updated_at":"2025-08-21T12:38:22.558Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27685509,"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","status":"online","status_checked_at":"2025-12-12T02:00:06.775Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["parameterised-tests","rust","test-fixtures","unit-testing"],"created_at":"2025-12-12T15:33:22.624Z","updated_at":"2025-12-12T15:33:23.467Z","avatar_url":"https://github.com/mindsbackyard.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Galvanic-test: easier test setup for Rust\n[![Build Status](https://travis-ci.org/mindsbackyard/galvanic-test.svg?branch=master)](https://travis-ci.org/mindsbackyard/galvanic-test)\n[![Crates.io](https://img.shields.io/crates/v/galvanic-test.svg)](https://crates.io/crates/galvanic-test)\n\nThis crate provides a framework for creating test suites, managing their shared dependencies, and for writing parameterised tests.\n\n * supports test fixtures to handle setup/tear-down of test dependencies\n * test fixtures with parameters provide more flexibility in test setups\n * parameterised tests---write your test once and verify it in different scenarios\n * automatic dependency injection of test fixtures into your tests\n * richer test design with **[galvanic-assert](https://www.github.com/mindsbackyard/galvanic-assert)**---express more specific properties of parameterised tests\n * test suites integrate with **[galvanic-mock](https://www.github.com/mindsbackyard/galvanic-mock)**---no manual `#[use_mocks]` is needed\n * other panic-based assertion and mocking frameworks of your choice can be used too\n\n The crate is part of **galvanic**---a complete test framework for **Rust**.\n The framework is shipped in three parts, so you can choose to use only the parts you need.\n\n## A short introduction to galvanic-test\n\n**Galvanic-test** simplifies the setup and tear-down of your test environments and helps you to organise your tests.\nEverything you already know about Rust testing should still apply.\n\nTests are organised in test suites which are either named or anonymous.\n```Rust\nuse galvanic_test::test_suite;\n\n// test suites are only built when a test is executed, e.g., with `cargo test`\ntest_suite! {\n    // for anonymous test suites remove the name directive\n    name my_test_suite;\n\n    // suites act as modules and may contain any item\n    fn calc(a: i32, b: i32) -\u003e i32 { a*b }\n\n    // instead of `fn`, `test` defines a test item.\n    test simple_first_test() {\n        assert_eq!(3*2, 6);\n    }\n\n    // attributes can usually be applied as for functions, e.g., #[should_panic(expected = \"...\")] is curently not supported\n    #[should_panic]\n    test another_test() {\n        assert_eq!(calc(3,2), 7);\n    }\n}\n```\n\nThe most powerful part of **galvanic-test** are test fixtures to manage your test environments.\nA test fixture is a piece of code which setups *one* specific part of a test and makes sure that it's torn down after the test executed (even if it failed).\nIf you know [pytest](https://docs.pytest.org/en/latest/) you should feel at home.\nIf you have experience with XUnit-style frameworks, e.g., JUnit, CPPUnit, ...; then you can think about fixtures as different `before`/`after` blocks which belong together.\n```Rust\nuse galvanic_test::test_suite;\n\ntest_suite! {\n    use std::fs::{File, remove_file};\n    use std::io::prelude::*;\n\n    fixture bogus_number() -\u003e i32 {\n        setup(\u0026mut self) {\n            42\n        }\n    }\n\n    fixture input_file(file_name: String, content: String) -\u003e File {\n        members {\n            file_path: Option\u003cString\u003e\n        }\n        setup(\u0026mut self) {\n            let file_path = format!(\"/tmp/{}.txt\", self.file_name);\n            self.file_path = Some(file_path.clone());\n            {\n                let mut file = File::create(\u0026file_path).expect(\"Could not create file.\");\n                file.write_all(self.content.as_bytes()).expect(\"Could not write input.\");\n            }\n            File::open(\u0026file_path).expect(\"Could not open file.\")\n        }\n        // tear_down is optional\n        tear_down(\u0026self) {\n            remove_file(self.file_path.as_ref().unwrap()).expect(\"Could not delete file.\")\n        }\n    }\n\n    // fixtures are arguments to the tests\n    test a_test_using_a_fixture(bogus_number) {\n        assert_eq!(21*2, bogus_number.val);\n    }\n\n    // fixtures with arguments must receive the required values\n    test another_test_using_fixtures(input_file(String::from(\"my_file\"), String::from(\"The stored number is: 42\"))) {\n        let mut read_content = String::new();\n        input_file.val.read_to_string(\u0026mut read_content).expect(\"Couldn't read 'my_file'\");\n\n        assert_eq!(\u0026read_content, input_file.params.content);\n    }\n}\n```\n\nTest fixtures enable us also to run the same test code with different parameterisations.\nThis can significantly reduce our work required for testing complex code with multiple execution paths.\n```Rust\ntest_suite! {\n    fixture product(x: u32, y: u32) -\u003e u32 {\n        params {\n            vec![(2,3), (2,4), (1,6), (1,5), (0,100)].into_iter()\n        }\n        setup(\u0026mut self) {\n            self.x * self.y\n        }\n    }\n\n    test a_parameterised_test_case(product) {\n        let wrong_product = (0 .. *product.params.y).fold(0, |p,_| p + product.params.x) - product.params.y%2;\n        // fails for (2,3) \u0026 (1,5)\n        assert_eq!(wrong_product, product.val)\n    }\n}\n```\n\n## Documentation\n\n**Galvanic-test** simplifies the setup of shared test environments, i.e., it helps us to create and reset the resources needed by our tests work properly.\n\nIt is recommended that you add `galvanic-test` as a dev-dependency in your `Cargo.toml`.\nMake sure to use an appropriate version specification.\nThe crate follows semantic versioning.\n\nFor Rust edition 2018 use a version number of at least `0.2`\n```toml\n[dev-dependencies]\ngalvanic-test = \"0.2\"\n```\nAfter specifying the dependency we can import the `test_suite` macro as follows.\n```Rust\nuse galvanic_test::test_suite;\n```\nWhen using `galvanic-test` as a dev-dependency make sure that the `use` statement is only reachable when your crate is compiled when tests are enabled, e.g., wrap it in a `#[cfg(test)]` annotated module.\n\n### Rust version before edition 2018\nFor using the crate with a Rust version before edition 2018 use a version number up to  `0.1.5`\n```toml\n[dev-dependencies]\ngalvanic-test = \"0.1.5\"\n```\nAfter specifying the dependency we include the library with enabled macros in our `main.rs`,`lib.rs`, and/or our integration tests in `tests/`.\n```Rust\n#[cfg(test) #[macro_use] extern crate galvanic_test;\n```\nWhen using `galvanic-test` as a dev-dependency make sure that any macro of `galvanic-test` is only reachable when tests are enabled.\n\n### Creating test suites for grouping tests\n\nBefore we start writing tests we have a look at how to group them.\nTests are organized in test suites.\nA test suite takes care of several things:\n* They create a private module to group test cases and test fixtures.\n* They are only built if tests are built, e.g., using `cargo test`.\n* Test fixtures defined in the suite can be injected into its test cases.\n* If the `galvanic_mock_integration` feature is enabled then the test suite uses an implicit `#[use_mocks]` directive. (*nightly*)\n\nThey come in two varieties: *anonymous* and *named*.\nTo create a *anonymous* test suite we use the `test_suite!` macro.\n```Rust\ntest_suite! {\n    // ...\n}\n```\nFor easier location of a failing test case it is recommended to name a test suite.\n```Rust\ntest_suite! {\n    name some_identifer_naming_the_suite;\n    // ...\n}\n```\nNote that the `name` directive must occur as the first element of the suite.\n\n### Writing tests in test suites\n\nNow that we have defined a test suite, we can fill it with test cases.\nA test case is defined as a `test` item.\n```Rust\ntest_suite! {\n    test my_first_test_case() {\n        // ... some assertions\n        assert_eq!(1+1, 2);\n    }\n}\n```\nIf we want to define a test which is expected to panic we can simply use the `#[should_panic]` attribute or if we need more fine grained control we may use `galvanic-assert`'s `assert_that!(..., panics);` macro.\n```Rust\ntest_suite! {\n    #[should_panic]\n    test a_panicking_test_case() {\n        // ... some failing assertion\n        assert_eq!(1+1, 4);\n    }\n    test a_panicking_test_case_using_galvanic_assert() {\n        assert_that(panic(\"No towels!\"), panics);\n    }\n}\n```\nSo far test cases behave similar to functions annotated with `#[test]` as in simple Rust unit tests.\nThough, test cases defined as a `test` item support automatic injection of test fixtures and parametrisation, as we will see later.\n\n### Adding test fixtures for test resource management\n\nTests often depend on some resources of the test environment, e.g., objects used by the test, files with input, etc.\nAll those things must be created at the beginning of the test and torn down at the end of the test.\nIf we forget or mess up one of those tasks we introduce errors in test code, which is actually not central to the test.\nFurther if many parts of these environments are the same or similar for several test cases then the problem gets even worse.\n\nTo keep our tests clean we do not want to code setup and tear down tasks multiple times.\nTherefore we write a *test fixture* for each resource.\n```Rust\nfixture a_number() -\u003e i32 {\n    setup(\u0026mut self) {\n        42\n    }\n    tear_down(\u0026self) {\n        println!(\"Cleaning up ...\");\n    }\n}\n```\nEvery fixture definition consists of the following parts:\n* the `fixture` keyword\n* a *name*: `a_number` in our example\n* a list of typed arguments: *none* in our example\n* the *type* of the *resource* managed by the fixture: `i32` here\n* a required `setup` block which receives the fixture (`self`) as a mutable borrow and must return a resource of the type specified by the fixture\n* an *optional* `tear_down` block which receives the fixture (`self`) as an immutable borrow\n\nTo use our new fixture in a test it must be defined in the same `test_suite!`.\nThe fixtures required by a test are given as parameters for test case by name.\nBefore the test is executed, `setup` method is invoked.\nIts return value is then wrapped in a `FixtureBinding` and the binding is injected into test case.\nThe return value can then be accessed by the binding's `val` member.\n```Rust\ntest a_test_using_a_fixture(a_number) {\n    assert_eq!(a_number.val, 42);\n}\n```\n\n#### Test fixtures with arguments\n\nOften setting up exactly the same resource for several tests is not enough and we'd like to parameterise the `setup`/`tear_down` code.\nWe can do so by specifying arguments for the fixture.\n```Rust\nfixture offset_number(offset: i32) -\u003e i32 {\n    setup(\u0026mut self) {\n        self.offset + 42\n    }\n    tear_down(\u0026self) {\n        println!(\"Cleaning up a number with offset {} ...\", self.offset);\n    }\n}\n```\nThe arguments are then accessible as members of the fixture.\nA test can then specify the required arguments when requesting the fixture.\nThe arguments passed to the fixture are accessible in the test case through the `FixtureBinding`'s `params` member by the names used in the fixture definition.\n```Rust\ntest a_test_using_a_fixture(offset_number(8)) {\n    assert_eq!(offset_number.val, 42 + offset_number.params.offset);\n}\n```\n\n#### Sharing data between setup() and tear_down()\n\nWe've seen that fixture arguments are available both in the `setup` and `tear_down` blocks via `self`.\nHowever there are situations where we depend on some external input, e.g., the system time, a random number, both in our setup code and tear-down code to, e.g., create unique file names or other identifiers.\nWith the facilities shown so far we have no (non-hacky) way to transfer the information.\n\nTo get around this issue we can define member variables for our fixtures.\nA member variable is accessible via `self` and is always an `Option` which is initialised with `None`.\nThe `setup` block may then overwrite the members' values (therefore its `\u0026mut self`).\n\nTo declare member variables we need to place a `members` block before the `setup` block and list our variable declarations ase we would in a `struct`.\n```Rust\nfixture offset_number() -\u003e i32 {\n    members {\n        some_identifier: Option\u003ci32\u003e\n    }\n    setup(\u0026mut self) {\n        self.some_identifier = Some(12)\n        42\n    }\n    tear_down(\u0026self) {\n        println!(\"Cleaning up a fixture with identifier {} ...\", self.some_identifier.as_ref().unwrap();\n    }\n}\n```\n\n### Writing parameterised tests and fixtures\n\nA very powerful feature of `galvanic-test` is the ability to parameterise tests.\nA parameterised test case is run with several different initialisations of its fixtures.\n\nFirst we need a test case which accepts one or multiple fixtures.\nLet's write a test which calculates the product of two numbers `(x,y)` by summing `x`, `y`-times.\n```Rust\ntest parameterised_test(product) {\n    let sum: u32 = (0..product.params.y).fold(0, |a,b| a + product.params.x);\n    assert_eq!(sum, product.val);\n}\n```\n\nWe want to test this code snippet with different values to test the border cases and equivalence classes.\nFor we create a `product` fixture with arguments `x` and `y` and let the `setup` block calculate the product of the two numbers.\nTo make the fixture parameterised we add a `params` block at the beginning.\nThe block must return an `Iterator\u003cR\u003e` where `R` is the type of the fixture's return value.\n```Rust\nfixture product(x: u32, y: u32) -\u003e u32 {\n    params {\n        vec![(2,3), (1,4), (0,100)].into_iter()\n    }\n    setup(\u0026mut self) {\n        self.x * self.y\n    }\n}\n```\n\nNow if we run our tests each test case with takes the `product` fixture as an argument without supplying parameters to the fixture will take the values from the `params` block instead.\nThe `setup` and `tear_down` block will be executed before/after each parameterisation.\n\nIf the test case takes multiple parameterised fixtures then all possible combinations (the cross-product) will be evaluated.\nAgain before/after each parameterisation **all** `setup`/`tear_down` blocks of the parameterised fixtures will be executed.\n\nIf on the other hand you provide parameters to a parameterised fixture, as shown below, then only that parameterisation will be considered for the fixture.\n```Rust\ntest parameterised_test(product(3,8)) {\n    let sum: u32 = (0..product.params.y).fold(0, |a,b| a + product.params.x);\n    assert_eq!(sum, 24);\n}\n```\n\n#### Errors, `#[should_panic]`, and parameterised fixtures\n\nLet's see what happens if a test fails.\n```Rust\ntest failing_parameterised_test(product) {\n    let sum: i32 = (0..*product.params.y).fold(0, |a,b| a + product.params.x);\n    assert_eq!(sum, product.val - product.params.x%2)\n}\n```\n\nThe framework will show you all parameterisations which triggered an error so debugging will be easier.\n```\n...\nrunning 1 test\nthread 'test::parameterised_test' panicked at 'assertion failed: `(left == right)`\n  left: `4`,\n right: `3`', src/main.rs:17:8\nnote: Run with `RUST_BACKTRACE=1` for a backtrace.\nThe above error occured with the following parameterisation of the test case:\n    product { x: 1, y: 4 }\n\nthread 'test::parameterised_test' panicked at 'Some parameterised test cases failed', src/main.rs:3:0\ntest test::parameterised_test ... FAILED\n...\n```\n\nBe careful when applying `#[should_panic]` to a parameterised test case.\nIn that case the test will succeed if **any** parameterisation fails.\nTo assert that all parameterisation fail it's recommended to use `assert_that!(..., panics)` from the `galvanic-assert` crate to treat panicking like a regular behaviour.\n\nFurther `#[should_panic(expected = \"message\")]` currently is not supported for tests with fixtures as the test output is modified to include information about the failing fixture parameterision.\n\n### Enabling Galvanic-mock integration\nIf you want to use **galvanic-mock** integration (only available on nightly) then add\n```Rust\n#[macro_use] extern crate galvanic_test;\n#![feature(proc_macro)]\nextern crate galvanic_mock;\n```\nand enable the `galvanic_mock_integration` feature in your `Cargo.toml`\n```toml\n[dev-dependencies]\ngalvanic-test = { version = \"*\", features = [\"galvanic_mock_integration\"] }\ngalvanic-mock = \"*\" # replace with the correct version\n```\n\nAfterwards each test suite will automatically apply the `#[use_mocks]` attribute so you can use fixtures to return actual mock objects.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmindsbackyard%2Fgalvanic-test","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmindsbackyard%2Fgalvanic-test","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmindsbackyard%2Fgalvanic-test/lists"}