[−][src]Crate diesel_factories
This is an implementation the test factory pattern made to work with Diesel.
Example usage:
#[macro_use] extern crate diesel; use diesel_factories::{Association, Factory}; use diesel::{pg::PgConnection, prelude::*}; // Tell Diesel what our schema is mod schema { table! { countries (id) { id -> Integer, name -> Text, } } table! { cities (id) { id -> Integer, name -> Text, country_id -> Integer, } } } // Our city model #[derive(Clone, Queryable)] struct City { pub id: i32, pub name: String, pub country_id: i32, } #[derive(Clone, Factory)] #[factory( // model type our factory inserts model = "City", // table the model belongs to table = "crate::schema::cities", // connection type you use. Defaults to `PgConnection` connection = "diesel::pg::PgConnection", // type of primary key. Defaults to `i32` id = "i32", )] struct CityFactory<'a> { pub name: String, // A `CityFactory` is associated to either an inserted `&'a Country` or a `CountryFactory` // instance. pub country: Association<'a, Country, CountryFactory>, } // We make new factory instances through the `Default` trait impl<'a> Default for CityFactory<'a> { fn default() -> Self { Self { name: "Copenhagen".to_string(), // `default` will return an `Association` with a `CountryFactory`. No inserts happen // here. // // This is the same as `Association::Factory(CountryFactory::default())`. country: Association::default(), } } } // The same setup, but for `Country` #[derive(Clone, Queryable)] struct Country { pub id: i32, pub name: String, } #[derive(Clone, Factory)] #[factory( model = "Country", table = "crate::schema::countries", connection = "diesel::pg::PgConnection", id = "i32", )] struct CountryFactory { pub name: String, } impl Default for CountryFactory { fn default() -> Self { Self { name: "Denmark".into(), } } } // Usage fn basic_usage() { let con = establish_connection(); let city = CityFactory::default().insert(&con); assert_eq!("Copenhagen", city.name); let country = find_country_by_id(city.country_id, &con); assert_eq!("Denmark", country.name); assert_eq!(1, count_cities(&con)); assert_eq!(1, count_countries(&con)); } fn setting_fields() { let con = establish_connection(); let city = CityFactory::default() .name("Amsterdam") .country(CountryFactory::default().name("Netherlands")) .insert(&con); assert_eq!("Amsterdam", city.name); let country = find_country_by_id(city.country_id, &con); assert_eq!("Netherlands", country.name); assert_eq!(1, count_cities(&con)); assert_eq!(1, count_countries(&con)); } fn multiple_models_with_same_association() { let con = establish_connection(); let netherlands = CountryFactory::default() .name("Netherlands") .insert(&con); let amsterdam = CityFactory::default() .name("Amsterdam") .country(&netherlands) .insert(&con); let hague = CityFactory::default() .name("The Hague") .country(&netherlands) .insert(&con); assert_eq!(amsterdam.country_id, hague.country_id); assert_eq!(2, count_cities(&con)); assert_eq!(1, count_countries(&con)); } // Utility functions just for demo'ing fn count_cities(con: &PgConnection) -> i64 { use crate::schema::cities; use diesel::dsl::count_star; cities::table.select(count_star()).first(con).unwrap() } fn count_countries(con: &PgConnection) -> i64 { use crate::schema::countries; use diesel::dsl::count_star; countries::table.select(count_star()).first(con).unwrap() } fn find_country_by_id(input: i32, con: &PgConnection) -> Country { use crate::schema::countries::dsl::*; countries .filter(id.eq(&input)) .first::<Country>(con) .unwrap() }
#[derive(Factory)]
Attributes
Name | Description | Example | Default |
---|---|---|---|
model | Model type your factory inserts | "City" | None, required |
table | Table your model belongs to | "crate::schema::cities" | None, required |
connection | The connection type your app uses | "MysqlConnection" | "diesel::pg::PgConnection" |
id | The type of your table's primary key | "i64" | "i32" |
Builder methods
Besides implementing Factory
for your struct it will also derive builder methods for easily customizing each field. The generated code looks something like this:
struct CountryFactory { pub name: String, } // This is what gets generated for each field impl CountryFactory { fn name<T: Into<String>>(mut self, new: T) -> Self { self.name = new.into(); self } } // So you can do this CountryFactory::default().name("Amsterdam");
Builder methods for associations
The builder methods generated for Association
fields are a bit different. If you have a factory like:
#[derive(Clone, Factory)] #[factory( model = "City", table = "crate::schema::cities", )] struct CityFactory<'a> { pub name: String, pub country: Association<'a, Country, CountryFactory>, }
You'll be able to call country
either with an owned CountryFactory
:
let country_factory = CountryFactory::default(); CityFactory::default().country(country_factory);
Or a borrowed Country
:
let country = Country { id: 1, name: "Denmark".into() }; CityFactory::default().country(&country);
This should prevent bugs where you have multiple factory instances sharing some association that you mutate halfway through a test.
Optional associations
If your model has a nullable association you can do this:
#[derive(Clone, Factory)] #[factory( model = "User", table = "crate::schema::users", )] struct UserFactory<'a> { pub name: String, pub country: Option<Association<'a, Country, CountryFactory>>, } impl<'a> Default for UserFactory<'a> { fn default() -> Self { Self { name: "Bob".into(), country: None, } } } // Setting `country` to a `CountryFactory` let country_factory = CountryFactory::default(); UserFactory::default().country(Some(country_factory)); // Setting `country` to a `Country` let country = Country { id: 1, name: "Denmark".into() }; UserFactory::default().country(Some(&country)); // Setting `country` to `None` UserFactory::default().country(Option::<CountryFactory>::None); UserFactory::default().country(Option::<&Country>::None);
Re-exports
pub use diesel_factories_code_gen::Factory; |
Enums
Association | A "belongs to" association that may or may not have been inserted yet. |
Traits
Factory | A generic factory trait. |
Functions
sequence | Utility function for generating unique ids or strings in factories.
Each time |