In this code-along, we'll refactor a tightly coupled application to use dependency injection. We'll extract interfaces for our dependencies and inject them through constructors to make the code more modular and testable.
// Before: Tightly coupled code public class OrderService { private final MySQLOrderRepository repository = new MySQLOrderRepository(); private final SmtpEmailSender emailSender = new SmtpEmailSender(); public void createOrder(Order order) { repository.save(order); emailSender.sendOrderConfirmation(order); } } // After: Dependency injection public class OrderService { private final OrderRepository repository; private final EmailSender emailSender; public OrderService(OrderRepository repository, EmailSender emailSender) { this.repository = repository; this.emailSender = emailSender; } public void createOrder(Order order) { repository.save(order); emailSender.sendOrderConfirmation(order); } }
In this code-along, we'll build a feature using the Test-Driven Development approach while using mocks to isolate our system under test. We'll write tests first, implement the minimum code to make them pass, and then refactor.
// 1. First we write a test with mocks @Test void shouldProcessOrderAndNotifyCustomer() { // Arrange Order testOrder = new Order("123", "Test Customer", 99.99); OrderRepository mockRepository = mock(OrderRepository.class); NotificationService mockNotification = mock(NotificationService.class); OrderProcessor processor = new OrderProcessor(mockRepository, mockNotification); // Act processor.processOrder(testOrder); // Assert verify(mockRepository).saveOrder(testOrder); verify(mockNotification).notifyCustomer(testOrder.getCustomerEmail(), contains("Order 123 processed")); } // 2. Then we implement the minimum code to make the test pass public class OrderProcessor { private final OrderRepository repository; private final NotificationService notificationService; public OrderProcessor(OrderRepository repository, NotificationService notificationService) { this.repository = repository; this.notificationService = notificationService; } public void processOrder(Order order) { repository.saveOrder(order); notificationService.notifyCustomer(order.getCustomerEmail(), "Order " + order.getId() + " processed"); } }