Sprint Challenge: Library Service

Overview

In this Sprint Challenge, you'll apply the patterns and practices you've learned throughout the sprint to build a Library Service. This challenge will test your understanding of dependency injection, test-driven development, and mocking techniques.

You'll build a service that manages books, patrons, and borrowing functions, with a focus on maintainable, testable code.

Challenge Requirements

Your task is to implement a Library Service with the following components:

  • Book Repository - For storing and retrieving book information
  • Patron Repository - For storing and retrieving patron information
  • Borrowing Service - For managing the borrowing and returning of books
  • Notification Service - For sending notifications about due dates, overdue books, etc.

You'll use dependency injection to create a loosely coupled design, and you'll write tests for each component using TDD and mocking techniques.

Core Requirements

1. Dependency Injection

  • Use constructor-based dependency injection
  • Define interfaces for all repositories and services
  • Ensure your service implementations depend on interfaces, not concrete implementations

2. Test-Driven Development

  • Write tests before implementing the functionality
  • Follow the red-green-refactor cycle
  • Achieve high test coverage for your business logic

3. Mocking

  • Use Mockito to mock dependencies in your tests
  • Verify interactions between components
  • Use argument captors where appropriate

Functional Requirements

  1. Book Management
    • Add new books to the library
    • Find books by ID, title, or author
    • Update book information
    • Remove books from the library
  2. Patron Management
    • Register new patrons
    • Find patrons by ID or name
    • Update patron information
    • Deactivate patron accounts
  3. Borrowing System
    • Check out books to patrons
    • Return books to the library
    • Track due dates for borrowed books
    • Handle overdue books and fines
  4. Notification System
    • Send checkout confirmations
    • Send due date reminders
    • Send overdue notifications

Example Code Structure

// Interfaces
public interface BookRepository {
    Book findById(String id);
    List findByTitle(String title);
    List findByAuthor(String author);
    void save(Book book);
    void delete(String id);
}

public interface BorrowingService {
    BorrowingReceipt borrowBook(String patronId, String bookId);
    ReturnReceipt returnBook(String patronId, String bookId);
    List getBorrowedBooks(String patronId);
    List getOverdueBooks();
}

// Implementation with dependency injection
public class BorrowingServiceImpl implements BorrowingService {
    private final BookRepository bookRepository;
    private final PatronRepository patronRepository;
    private final NotificationService notificationService;
    
    public BorrowingServiceImpl(
        BookRepository bookRepository, 
        PatronRepository patronRepository, 
        NotificationService notificationService
    ) {
        this.bookRepository = bookRepository;
        this.patronRepository = patronRepository;
        this.notificationService = notificationService;
    }
    
    @Override
    public BorrowingReceipt borrowBook(String patronId, String bookId) {
        // Implementation...
    }
    
    // More methods...
}

// Test using TDD and mocking
@Test
public void shouldNotAllowBorrowingUnavailableBook() {
    // Arrange
    BookRepository mockBookRepo = mock(BookRepository.class);
    PatronRepository mockPatronRepo = mock(PatronRepository.class);
    NotificationService mockNotification = mock(NotificationService.class);
    
    Book unavailableBook = new Book("123", "Test Book", "Author");
    unavailableBook.setAvailable(false);
    
    Patron patron = new Patron("456", "Test Patron");
    
    when(mockBookRepo.findById("123")).thenReturn(unavailableBook);
    when(mockPatronRepo.findById("456")).thenReturn(patron);
    
    BorrowingService service = new BorrowingServiceImpl(
        mockBookRepo, mockPatronRepo, mockNotification);
    
    // Act & Assert
    assertThrows(BookUnavailableException.class, () -> {
        service.borrowBook("456", "123");
    });
    
    verify(mockBookRepo).findById("123");
    verify(mockPatronRepo).findById("456");
    verify(mockNotification, never()).sendBorrowingConfirmation(any(), any());
}

Submission Requirements

  • Clone the starter repository from GitHub Classroom
  • Implement all the required functionality
  • Ensure all tests pass
  • Submit your solution through GitHub Classroom by the deadline

Resources