(I’m sorry in advance, since this problem is a bit hard to put into text)
I’m using axum. My main.rs
loads up by calling a create_app
function that takes a set of repositories as arguments. I want to use dependency injection for these repositories (swap them out against mocks during tests).
pub fn create_app(
repo_org: Arc<impl RepositoryOrganization>,
) -> Router {
let service_organization = OrganizationService::new(repo_org);
create_router(
service_organization,
)
}
Here is an example repository trait:
#[automock]
#[async_trait]
pub trait RepositoryOrganization: Send + Sync + 'static {
async fn create(
&self,
) -> Result<OrganizationDto, sqlx::Error>;
}
In my testing module I setup my app using mocks
async fn setup_test_app() -> TestApp {
let repo_org = Arc::new(MockRepositoryOrganization::new());
let router = create_app(
repo_org.clone(),
);
TestApp {
repo_org: repo_org.clone(),
}
}
During tests I want to use the mock implementation. However, for this to work a mutable borrow is required.
async fn test_create_organization() {
let TestApp {
router, mut repo_org, .. // <- mut here
} = setup_test_app().await;
repo_org
.expect_create()
.with(
eq(Uuid::nil()),
function(|dto: &CreateOrganizationDto| dto.name == "Test Org"),
)
.times(1)
.returning(|_, _| {
Ok(OrganizationDto {
id: Uuid::now_v7(),
name: "Test Org".to_string(),
created_at: Utc::now().naive_utc(),
updated_at: Utc::now().naive_utc(),
})
});
}
This errors because I cannot borrow mutably from an Arc
.
My next approach would be to use a Mutex
(I’m now to rust so it gets a bit scary here).
pub fn create_app(
repo_org: Arc<Mutex<dyn RepositoryOrganization>>,
) -> Router {
// ... rest of the function remains the same
}
I really dislike this pattern because I’m rewriting my app logic to accomodate tests.
Rust seems to have a pattern called Interior Mutability.
This relates to the Mutex
approach. However, rather than me having to apply the Mutex, I feel like mockall
may have a setting/feature where it internally uses a Mutex
to mutate behind the immutable reference (?).
Anyway, I’m desparately looking for am approach that does not require me to add Mutex
into my app logic and hope someone might be able to help.
1