Тестовые задания Java Junior — почти всегда Spring Boot: CRUD API с базой данных, валидацией, тестами. Разбираем типичный кейс от начала до отправки.
Тестовое задание junior разработчика: как не завалить
Типичные форматы
CRUD REST API на Spring Boot: управление пользователями, заказами, товарами. JPA + PostgreSQL/H2.
Сервис с бизнес-логикой: «реализуй сервис обработки платежей» с валидацией, исключениями, логированием.
Рефакторинг готового кода: дают плохой код и просят улучшить — проверяют понимание принципов.
Разбор кейса: API для библиотеки книг
Типичное условие:
> Реализуй REST API для управления библиотекой. Книга имеет: title, author, isbn, publishedYear. Требования:
> - CRUD для книг
> - Поиск по автору и году издания
> - Валидация входных данных
> - Unit-тесты для сервисного слоя
Стек: Java 17, Spring Boot 3, Spring Data JPA, PostgreSQL (или H2 для тестов), Maven.
Структура проекта (трёхслойная архитектура)
```
library-api/
├── src/main/java/com/example/library/
│ ├── controller/
│ │ └── BookController.java
│ ├── service/
│ │ ├── BookService.java
│ │ └── BookServiceImpl.java
│ ├── repository/
│ │ └── BookRepository.java
│ ├── model/
│ │ └── Book.java
│ ├── dto/
│ │ ├── BookRequest.java
│ │ └── BookResponse.java
│ └── exception/
│ ├── BookNotFoundException.java
│ └── GlobalExceptionHandler.java
├── src/test/java/
│ └── service/BookServiceTest.java
├── src/main/resources/
│ └── application.yml
└── README.md
```
Ключевые моменты
DTO — обязательно. Не возвращайте Entity напрямую из контроллера. `BookRequest` для входных данных, `BookResponse` для ответа.
Валидация через Bean Validation:
```java
public class BookRequest {
@NotBlank(message = "Title is required")
private String title;
@NotBlank
private String author;
@Pattern(regexp = "\\d{13}", message = "ISBN must be 13 digits")
private String isbn;
@Min(value = 1000)
@Max(value = 2100)
private Integer publishedYear;
}
```
Глобальный обработчик исключений:
```java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BookNotFoundException.class)
public ResponseEntity<String> handleNotFound(BookNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage());
}
}
```
Тесты сервисного слоя с Mockito:
```java
@ExtendWith(MockitoExtension.class)
class BookServiceTest {
@Mock
private BookRepository bookRepository;
@InjectMocks
private BookServiceImpl bookService;
@Test
void shouldThrowWhenBookNotFound() {
when(bookRepository.findById(999L)).thenReturn(Optional.empty());
assertThrows(BookNotFoundException.class, () -> bookService.getById(999L));
}
}
```
Application.yml вместо .properties
```yaml
spring:
datasource:
url: ${DB_URL:jdbc:h2:mem:testdb}
username: ${DB_USER:sa}
password: ${DB_PASSWORD:}
jpa:
hibernate:
ddl-auto: create-drop
show-sql: false
```
Переменные окружения через `${VAR:default}` — секреты не захардкожены.
Что проверяют в коде
Разделение ответственности: контроллер не содержит бизнес-логику, репозиторий — только запросы к БД.
Правильные HTTP-коды: создание → 201, не найдено → 404, ошибка валидации → 400.
Тесты с моками, а не интеграционные на реальной БД. Быстро и изолированно.
Именование в стиле Java: camelCase, классы с заглавной, интерфейсы без `I` префикса.
FAQ
Нужен ли Lombok?
Можно использовать — экономит бойлерплейт. Укажите в README.
H2 или PostgreSQL?
H2 в памяти — удобен для тестов. Для production-конфига покажите PostgreSQL через переменные окружения.
Нужна ли аутентификация?
Если не требовали — не добавляйте. Лучше сделать хорошо требуемое, чем плохо необязательное.
---