Use the crate mockall to mock the email service in integration tests

This commit is contained in:
Greg Burri 2025-05-02 13:38:41 +02:00
parent 3626f8a11b
commit 8c70f90234
5 changed files with 109 additions and 23 deletions

View file

@ -56,3 +56,4 @@ thiserror = "2"
axum-test = "17"
cookie = "0.18"
scraper = "0.23"
mockall = "0.13"

View file

@ -1,10 +1,11 @@
use std::error::Error;
use std::{error::Error, sync::Arc};
use axum_test::TestServer;
use cookie::Cookie;
use mockall::predicate;
use scraper::{ElementRef, Html, Selector};
use recipes::app;
use recipes::{app, email};
use serde::Serialize;
mod utils;
@ -104,7 +105,18 @@ pub struct SignUpFormData {
#[tokio::test]
async fn sign_up() -> Result<(), Box<dyn Error>> {
// Arrange.
let state = utils::common_state().await?;
let mut mock_email_service = utils::mock_email::MockEmailService::new();
mock_email_service
.expect_send_email()
.with(
predicate::eq("president@spaceball.planet"),
predicate::always(),
predicate::always(),
)
.times(1)
.returning(|_email, _title, _message| Ok(()));
let state = utils::common_state_with_email_service(Arc::new(mock_email_service)).await?;
let server = TestServer::new(app::make_service(state))?;
// Act.
@ -122,7 +134,6 @@ async fn sign_up() -> Result<(), Box<dyn Error>> {
let document = Html::parse_document(&response.text());
assert_eq!(document.errors.len(), 0);
dbg!(response);
Ok(())
}

View file

@ -1,23 +1,20 @@
use std::sync::Arc;
use recipes::email;
use async_trait::async_trait;
use mockall::{mock, predicate::*};
pub struct MockEmailService;
use crate::email;
impl MockEmailService {
pub fn create_service() -> Arc<dyn email::EmailServiceTrait> {
Arc::new(Self {})
mock! {
pub EmailService {}
#[async_trait]
impl email::EmailServiceTrait for EmailService {
async fn send_email(&self, email: &str, title: &str, message: &str)
-> Result<(), email::Error>;
}
}
#[async_trait::async_trait]
impl email::EmailServiceTrait for MockEmailService {
async fn send_email(
&self,
_email: &str,
_title: &str,
_message: &str,
) -> Result<(), email::Error> {
Ok(())
}
// Default email service: will crash if `send_email` method is called.
pub fn new_mock_email_service() -> Arc<dyn email::EmailServiceTrait> {
Arc::new(MockEmailService::new())
}

View file

@ -1,10 +1,16 @@
use std::error::Error;
use std::{error::Error, sync::Arc};
use recipes::{app, config, data::db, log};
use recipes::{app, config, data::db, email, log};
mod mock_email;
pub mod mock_email;
pub async fn common_state() -> Result<app::AppState, Box<dyn Error>> {
common_state_with_email_service(mock_email::new_mock_email_service()).await
}
pub async fn common_state_with_email_service(
email_service: Arc<dyn email::EmailServiceTrait>,
) -> Result<app::AppState, Box<dyn Error>> {
let db_connection = db::Connection::new_in_memory().await?;
let config = config::Config::default();
let log = log::Log::new_no_log();
@ -12,7 +18,7 @@ pub async fn common_state() -> Result<app::AppState, Box<dyn Error>> {
config,
db_connection,
log,
email_service: mock_email::MockEmailService::create_service(),
email_service,
})
}