Skip to content

Commit c90df4a

Browse files
committed
refactor: add test builders for command dependencies
Implemented Proposal #4 - Test Builder Helpers Changes: - Added ProvisionCommandTestBuilder in provision.rs test module - Manages TempDir lifecycle automatically - Provides sensible defaults for all dependencies - Returns (command, temp_dir, ssh_credentials) tuple - Includes optional with_ssh_credentials() customization method - Added ConfigureCommandTestBuilder in configure.rs test module - Manages TempDir lifecycle automatically - Provides sensible defaults for all dependencies - Returns (command, temp_dir) tuple - Updated 5 provision tests to use ProvisionCommandTestBuilder - Updated 2 configure tests to use ConfigureCommandTestBuilder - Removed old create_mock_dependencies() functions from both files Rationale: - Reduces test boilerplate significantly - Eliminates confusing 8-tuple return from provision tests - Eliminates confusing 4-tuple return from configure tests - Self-contained builders manage their own TempDir lifecycle - Type-safe: returns properly typed values - Extensible: easy to add customization methods - Maintainable: changes to dependencies don't break all tests Impact: - Removed ~76 lines (old create_mock_dependencies functions) - Added ~92 lines (builder implementations) - Net change: +16 lines - Tests are now much more readable and maintainable - Before: let (r1, r2, r3, r4, r5, r6, r7, r8) = create_mock_dependencies(); - After: let (command, temp_dir, ssh_credentials) = ProvisionCommandTestBuilder::new().build(); - All 100 tests passing - All linters passing
1 parent e65b168 commit c90df4a

File tree

2 files changed

+137
-200
lines changed

2 files changed

+137
-200
lines changed

src/application/commands/configure.rs

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -266,30 +266,6 @@ mod tests {
266266
use super::*;
267267
use tempfile::TempDir;
268268

269-
// Helper function to create mock dependencies for testing
270-
#[allow(clippy::type_complexity)]
271-
fn create_mock_dependencies() -> (
272-
Arc<AnsibleClient>,
273-
Arc<dyn crate::shared::Clock>,
274-
Arc<dyn EnvironmentRepository>,
275-
TempDir,
276-
) {
277-
let temp_dir = TempDir::new().expect("Failed to create temp dir");
278-
let ansible_client = Arc::new(AnsibleClient::new(temp_dir.path()));
279-
280-
// Create clock
281-
let clock: Arc<dyn crate::shared::Clock> = Arc::new(crate::shared::SystemClock);
282-
283-
// Create repository
284-
let repository_factory =
285-
crate::infrastructure::persistence::repository_factory::RepositoryFactory::new(
286-
std::time::Duration::from_secs(30),
287-
);
288-
let repository = repository_factory.create(temp_dir.path().to_path_buf());
289-
290-
(ansible_client, clock, repository, temp_dir)
291-
}
292-
293269
// Helper function to create a test environment in Configuring state
294270
fn create_test_environment(_temp_dir: &TempDir) -> (Environment<Configuring>, TempDir) {
295271
use crate::domain::environment::testing::EnvironmentTestBuilder;
@@ -308,11 +284,46 @@ mod tests {
308284
)
309285
}
310286

287+
/// Test builder for `ConfigureCommand` that manages dependencies and lifecycle
288+
///
289+
/// This builder simplifies test setup by:
290+
/// - Managing `TempDir` lifecycle
291+
/// - Providing sensible defaults for all dependencies
292+
/// - Returning only the command and necessary test artifacts
293+
pub struct ConfigureCommandTestBuilder {
294+
temp_dir: TempDir,
295+
}
296+
297+
impl ConfigureCommandTestBuilder {
298+
/// Create a new test builder with default configuration
299+
pub fn new() -> Self {
300+
let temp_dir = TempDir::new().expect("Failed to create temp dir");
301+
Self { temp_dir }
302+
}
303+
304+
/// Build the `ConfigureCommand` with all dependencies
305+
///
306+
/// Returns: (`command`, `temp_dir`)
307+
/// The `temp_dir` must be kept alive for the duration of the test.
308+
pub fn build(self) -> (ConfigureCommand, TempDir) {
309+
let ansible_client = Arc::new(AnsibleClient::new(self.temp_dir.path()));
310+
let clock: Arc<dyn crate::shared::Clock> = Arc::new(crate::shared::SystemClock);
311+
312+
let repository_factory =
313+
crate::infrastructure::persistence::repository_factory::RepositoryFactory::new(
314+
std::time::Duration::from_secs(30),
315+
);
316+
let repository = repository_factory.create(self.temp_dir.path().to_path_buf());
317+
318+
let command = ConfigureCommand::new(ansible_client, clock, repository);
319+
320+
(command, self.temp_dir)
321+
}
322+
}
323+
311324
#[test]
312325
fn it_should_create_configure_command_with_all_dependencies() {
313-
let (ansible_client, clock, repository, _temp_dir) = create_mock_dependencies();
314-
315-
let command = ConfigureCommand::new(ansible_client, clock, repository);
326+
let (command, _temp_dir) = ConfigureCommandTestBuilder::new().build();
316327

317328
// Verify the command was created (basic structure test)
318329
// This test just verifies that the command can be created with the dependencies
@@ -334,9 +345,7 @@ mod tests {
334345
fn it_should_build_failure_context_from_command_error() {
335346
use chrono::{TimeZone, Utc};
336347

337-
let (ansible_client, clock, repository, temp_dir) = create_mock_dependencies();
338-
339-
let command = ConfigureCommand::new(ansible_client, clock, repository);
348+
let (command, temp_dir) = ConfigureCommandTestBuilder::new().build();
340349

341350
// Create test environment for trace generation
342351
let (environment, _env_temp_dir) = create_test_environment(&temp_dir);

0 commit comments

Comments
 (0)