[][src]Crate factori

A testing factory library for Rust, inspired by FactoryBot.

Factori aims to provide a clean, ergonomic syntax for instantiating test objects, without sacrificing type-safety.

This crate provides:

  • A factori!() macro which is used to define factories.
  • A create!() macro which is used to instantiate objects from factories.

Example

#[macro_use]
extern crate factori;

pub struct Vehicle {
    number_wheels: u8,
    electric: bool,
}

factori!(Vehicle, {
    default {
        number_wheels = 4,
        electric = false,
    }

    mixin bike {
        number_wheels = 2,
    }
});

fn main() {
    let default = create!(Vehicle);
    assert_eq!(default.number_wheels, 4);
    assert_eq!(default.electric, false);

    // Its type is Vehicle, nothing fancy:
    let vehicle: Vehicle = default;

    let three_wheels = create!(Vehicle, number_wheels: 3);
    assert_eq!(three_wheels.number_wheels, 3);

    let electric_bike = create!(Vehicle, :bike, electric: true);
    assert_eq!(electric_bike.number_wheels, 2);
    assert_eq!(electric_bike.electric, true);
}

More examples are available in the tests/ alongside the crate.

How it works

Behind the scenes, the factori!() macro generates some extra types to encode the default values and mixins for each factory.

The create!() macro expects the generated _Factori types to be in scope. If the factory is instantiated in the same module that it is defined, this will work as expected. If the factory is defined in a separate module, then it is recommended that you do a glob import to bring them into scope.

In most projects, you should expect to have a (or a few) factories modules which contain shared factories. In tests modules you can then use a glob import to bring all of the required types into scope without having them cluttering up your project's namespaces.

struct Vehicle {
    number_wheels: u8,
}

mod factories {
    use super::Vehicle;

    factori!(Vehicle, {
        default {
            number_wheels = 4
        }
    });
}

#[cfg(test)]
mod tests {
    use super::{Vehicle, factories::*};

    #[test]
    fn some_test() {
        let vehicle = create!(Vehicle);
        assert_eq!(vehicle.number_wheels, 4);
    }
}

The implementation details of the factori!() and create!() macros are considered private and you should not rely on any of the generated types or their names. However, the implementation is quite simple and you are encouraged to run cargo-expand in order to see the generated code.

The generated types are all prefixed with _Factori and are unlikely to clash with any types in your crate. It is a little gross but it is all in the name of testing convenience.

Error messages

The error messages coming from these macros are surprisingly good considering what they're doing. However, if you encounter weird error messages that aren't self-explanatory, please raise an issue on the GitHub repository.

Macros

create

A macro to instantiate an instance of a factory.

factori

A macro to define a factory for a type.