All Projects → nrxus → Faux

nrxus / Faux

Licence: mit
Traitless Mocking Library for Rust

Programming Languages

rust
11053 projects

Projects that are alternatives of or similar to Faux

Vue Cli Multi Page
基于vue-cli模板的多页面多路由项目,一个PC端页面入口,一个移动端页面入口,且有各自的路由, vue+webpack+vue-router+vuex+mock+axios
Stars: ✭ 145 (-23.68%)
Mutual labels:  mock
Gunit
GUnit - Google.Test/Google.Mock/Cucumber on steroids
Stars: ✭ 156 (-17.89%)
Mutual labels:  mock
Mocktopus
Mocking framework for Rust
Stars: ✭ 179 (-5.79%)
Mutual labels:  mock
Weld
Full fake REST API generator written with Rust
Stars: ✭ 146 (-23.16%)
Mutual labels:  mock
Aeromock
Lightweight mock web application server
Stars: ✭ 152 (-20%)
Mutual labels:  mock
Mockito
Most popular Mocking framework for unit tests written in Java
Stars: ✭ 12,453 (+6454.21%)
Mutual labels:  mock
Wabbit
Golang AMQP mocking library
Stars: ✭ 137 (-27.89%)
Mutual labels:  mock
Graphql Faker
🎲 Mock or extend your GraphQL API with faked data. No coding required.
Stars: ✭ 2,361 (+1142.63%)
Mutual labels:  mock
Httpretty
Intercept HTTP requests at the Python socket level. Fakes the whole socket module
Stars: ✭ 1,930 (+915.79%)
Mutual labels:  mock
Mockinizer
An okhttp / retrofit api call mocking library
Stars: ✭ 176 (-7.37%)
Mutual labels:  mock
Morphlingjs
A CLI to mock with meaningful data a REST API from a Swagger file
Stars: ✭ 148 (-22.11%)
Mutual labels:  mock
Easyfun
a project using react antd webpack es6
Stars: ✭ 150 (-21.05%)
Mutual labels:  mock
Raml Server
run a mocked server JUST based on a RAML API's definition .. zero coding
Stars: ✭ 158 (-16.84%)
Mutual labels:  mock
Easy mock api
easy mock json api
Stars: ✭ 145 (-23.68%)
Mutual labels:  mock
Killgrave
Simple way to generate mock servers written in Go
Stars: ✭ 180 (-5.26%)
Mutual labels:  mock
Smoke
💨 Simple yet powerful file-based mock server with recording abilities
Stars: ✭ 142 (-25.26%)
Mutual labels:  mock
Randomdata
Random data generator
Stars: ✭ 157 (-17.37%)
Mutual labels:  mock
Xhr Mock
Utility for mocking XMLHttpRequest.
Stars: ✭ 188 (-1.05%)
Mutual labels:  mock
Interceptor
A browser extension to mock AJAX requests at the browser level
Stars: ✭ 182 (-4.21%)
Mutual labels:  mock
Mocktail
A mock library for Dart inspired by mockito
Stars: ✭ 172 (-9.47%)
Mutual labels:  mock

faux   Latest Version rustc 1.45+ docs

faux is a traitless mocking library for stable Rust. It was inspired by mocktopus, a mocking library for nightly Rust that lets you mock any function. Unlike mocktopus, faux deliberately only allows for mocking public methods in structs.

See the API docs for more information.

faux is in its early alpha stages, so there are no guarantees of API stability.

Setup

faux will modify existing code at compile time to transform structs and their methods into mockable versions of themselves. faux makes liberal use of unsafe Rust features, so it is only recommended for use inside of tests. Add faux as a dev-dependency in Cargo.tomlto prevent usage in production code:

[dev-dependencies]
faux = "0.0.8"

faux provides two attributes: create and methods. Use these attributes for tagging your struct and its impl block respectively. Use Rust's #[cfg_attr(...)] to gate these attributes to the test config only.

#[cfg_attr(test, faux::create)]
pub struct MyStructToMock { /* fields */ }

#[cfg_attr(test, faux::methods)]
impl MyStructToMock { /* methods to mock */ }

Usage

mod client {
    // creates a mockable version of `UserClient`
    // generates an associated function, `UserClient::faux`, to create a mocked instance
    #[faux::create]
    pub struct UserClient { /* data of the client */ }

    pub struct User {
        pub name: String
    }

    // creates mockable version of every method in the impl
    #[faux::methods]
    impl UserClient {
        pub fn fetch(&self, id: usize) -> User {
            // does some network calls that we rather not do in tests
            User { name: "".into() }
        }
    }
}

use crate::client::UserClient;

pub struct Service {
    client: UserClient,
}

#[derive(Debug, PartialEq)]
pub struct UserData {
    pub id: usize,
    pub name: String,
}

impl Service {
    fn user_data(&self) -> UserData {
        let id = 3;
        let user = self.client.fetch(id);
        UserData { id, name: user.name }
    }
}

// A sample #[test] for Service that mocks the client::UserClient
fn main() {
    // create a mock of client::UserClient using `faux`
    let mut client = client::UserClient::faux();

    // set up what the mock should return
    faux::when!(client.fetch).then(|id| {
        assert_eq!(id, 3, "expected UserClient.fetch to receive user #3");
        client::User { name: "my user name".into() }
    });

    // prepare the subject for your test using the mocked client
    let subject = Service { client };

    // assert that your subject returns the expected data
    let expected = UserData { id: 3, name: String::from("my user name") };
    assert_eq!(subject.user_data(), expected);
}

Due to constraints with rustdocs, the above example tests in main() rather than a #[test] function. In real life, the faux attributes should be gated to #[cfg(test)].

Interactions With Other Proc Macros

faux makes no guarantees that it will work with other macro libraries. faux in theory should "just" work although with some caveats, in particular if they modify the signature of methods.

Unfortunately, the order of proc macros is not specified. However, in practive it seems to expand top-down (tested in Rust 1.42).

#[faux::create]
struct Foo { /*some items here */ }

#[faux::methods]
#[another_attribute]
impl Foo {
    /* some methods here */
}

In the snippet above, #[faux::methods] will expand first followed by #[another_attribute].

If faux does its expansion first then faux will effectively ignore the other macro and expand based on the code that the user wrote. If you want faux to treat the code in the impl block (or the struct) as-is, before the expansion then put it on the top.

If faux does its expansion after, then faux will morph the expanded version of the code, which might have a different signature than what you originally wrote. Note that the other proc macro's expansion may create code that faux cannot handle (e.g., explicit lifetimes).

For a concrete example, let's look at async-trait. async-trait effectively converts:

async fn run(&self, arg: Arg) -> Out {
    /* stuff inside */
}
fn run<'async>(&'async self, arg: Arg) -> Pin<Box<dyn std::future::Future<Output = Out> + Send + 'async>> {
    /* crazier stuff inside */
}

Because async-trait modifies the signature of the function to a signature that faux cannot handle (explicit lifetimes) then having async-trait do its expansion before faux would make faux not work. Note that even if faux could handle explicit lifetimes, our signature now it's so unwieldy that it would make mocks hard to work with. Because async-trait just wants an async function signature, and faux does not modify function signatures, it is okay for faux to expand first.

#[faux::methods]
#[async_trait]
impl MyStruct for MyTrait {
    async fn run(&self, arg: Arg) -> Out {
        /* stuff inside */
    }
}

Since no expansions came before, faux sees an async function, which it supports. faux does its magic assuming this is a normal async function, and then async-trait does its magic to convert the signature to something that can work on trait impls.

If you find a procedural macro that faux cannot handle please submit an issue to see if faux is doing something unexpected that conflicts with that macro.

Goal

faux was founded on the belief that traits with single implementations are an undue burden and an unnecessary layer of abstraction. It aims to create mocks out of user-defined structs, avoiding extra production code that exists solely for tests. In particular, faux does not rely on trait definitions for every mocked object, which would pollute their function signatures with either generics or trait objects.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].