Hello everyone,
I'm currently building a private API used as a backend for my application. I added a few features in it and everything is working fine. Now I want to do some testing because I tend to break old features when I'm adding a new one and it will save me some time. Since it's mostly a CRUD, I don't have a lot of unit testing to do. However, I do have a lot of integration testing to create.
What I've done so far was to modify my app from binary to libary, set up a "tests" folder to do my integration tests and create an employee_test.rs. In this employee_test, I try to test the creation of an employee.
type TestResult = Result<(), Box<dyn std::error::Error>>;
#[actix_rt::test]
async fn test_add_get_employee() -> TestResult {
let pool = common::config::setup_test_db().await;
let first_name = "TestFirst";
let last_name = "TestLast";
let title = "Test Engineer";
// Use the public constructor/factory method from Employee
let new_employee = Employee::create_test_employee(first_name, last_name, title);
// --- Test Execution ---
// Add the employee and get their ID
let employee_id = add_new_employee(&pool, new_employee.clone()).await?;
let retrieved_employee = get_employee_info(&pool, employee_id).await?;
assert_eq!(retrieved_employee.id, Some(employee_id));
sqlx::query("DELETE FROM employees WHERE id = $1")
.bind(employee_id)
.execute(&pool)
.await?;
Ok(())
}
Concerning my employee model :
#[cfg_attr(test, derive(Debug, PartialEq))]
#[derive(Serialize,Deserialize,FromRow,Clone, Default)]
#[sqlx(default)]
pub struct Employee {
pub id : Option<i32>,
first_name: String,
last_name: String,
title: String,
...
}
impl Employee {
pub fn create_test_employee(first_name: &str, last_name: &str, title: &str) -> Self {
Employee {
id: None,
first_name: first_name.to_string(),
last_name: last_name.to_string(),
title: title.to_string(),
...
}
}
}
pub async fn add_new_employee(pool: &PgPool, employee: Employee) -> Result<i32, EmployeeError> {
let id = sqlx::query_scalar(
r#"
INSERT INTO employees (
first_name, last_name, title
)
VALUES (
$1, $2, $3
)
RETURNING id
"#
)
.bind(employee.first_name)
.bind(employee.last_name)
.bind(employee.title)
.fetch_one(pool)
.await;
match id {
Ok(id) => Ok(id),
Err(e) => Err(EmployeeError::DatabaseError(e)),
}
}
As you can see, I only assert the id because the other fields can't be asserted.
My big issue is the property readability, should I set every field as public ? I've read that it won't be an issue if it's a private API but still, I'm kinda in a mixed feeling doing so. Is a getter/setter my solution ? Because it will make the file so much bigger and those getter setter will only be used for tests.
Do you have a better implementation idea ? Maybe my solution isn't really suitable for long term.
Packages used : actix-web, sqlx, serde