pub trait Factory {
type Model: Model + Serialize + for<'r> FromRow<'r, SqliteRow> + for<'r> FromRow<'r, PgRow> + HydrateRelated;
// Required method
fn build() -> Self::Model;
// Provided methods
fn create<'async_trait>( ) -> Pin<Box<dyn Future<Output = Result<Self::Model, FactoryError>> + Send + 'async_trait>>
where Self: Send + 'async_trait { ... }
fn create_with<'async_trait, F>(
tweak: F,
) -> Pin<Box<dyn Future<Output = Result<Self::Model, FactoryError>> + Send + 'async_trait>>
where F: FnOnce(&mut Self::Model) + Send + 'async_trait,
Self: Send + 'async_trait { ... }
fn create_batch<'async_trait>(
n: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<Self::Model>, FactoryError>> + Send + 'async_trait>>
where Self: Send + 'async_trait { ... }
}Expand description
A factory for producing realistic instances of a model — the factory_boy / FactoryBot shape, in Rust.
You define a zero-sized marker type and point it at a Model through
the associated type. The orphan rule is why the impl lives on a marker
rather than on the model: in a downstream test crate both the model and
this trait are foreign, so impl Factory for Plugin wouldn’t compile —
but impl Factory for PluginFactory (a local marker) does.
use umbral_testing::{Factory, fake::{Fake, faker::{lorem::en::*, company::en::*}}, seq};
struct PluginFactory;
impl Factory for PluginFactory {
type Model = Plugin;
fn build() -> Plugin {
let mut p = Plugin::default();
p.name = CompanyName().fake();
p.slug = format!("plugin-{}", seq()); // unique per call
p.short_description = Sentence(4..8).fake();
p
}
}
// In a test, after `App::builder()...build()` has set the ambient pool
// and the tables exist:
let one = PluginFactory::create().await?; // one row
let many = PluginFactory::create_batch(5).await?; // five rows
let featured = PluginFactory::create_with(|p| p.featured = true).await?;build is pure (no I/O); the create* methods
persist through the ORM against the ambient pool, so a built app must
be in scope. Combine with TestClient to then exercise a handler
against the rows the factory produced.
Required Associated Types§
Sourcetype Model: Model + Serialize + for<'r> FromRow<'r, SqliteRow> + for<'r> FromRow<'r, PgRow> + HydrateRelated
type Model: Model + Serialize + for<'r> FromRow<'r, SqliteRow> + for<'r> FromRow<'r, PgRow> + HydrateRelated
The model this factory produces. The bound set is exactly what
#[derive(Model)] already provides on every model (the ORM’s
create path needs Serialize + FromRow + HydrateRelated), so
in practice you only ever write type Model = YourModel;.
Required Methods§
Provided Methods§
Sourcefn create<'async_trait>() -> Pin<Box<dyn Future<Output = Result<Self::Model, FactoryError>> + Send + 'async_trait>>where
Self: Send + 'async_trait,
fn create<'async_trait>() -> Pin<Box<dyn Future<Output = Result<Self::Model, FactoryError>> + Send + 'async_trait>>where
Self: Send + 'async_trait,
Build and persist one row through the ORM.
Sourcefn create_with<'async_trait, F>(
tweak: F,
) -> Pin<Box<dyn Future<Output = Result<Self::Model, FactoryError>> + Send + 'async_trait>>
fn create_with<'async_trait, F>( tweak: F, ) -> Pin<Box<dyn Future<Output = Result<Self::Model, FactoryError>> + Send + 'async_trait>>
Build one row, apply tweak to override specific fields, then
persist. This is the create(featured = true) override hook.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".