getCommonFriends(Integer id1, Integer id2);
}
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/LegalFilmDate.java b/src/main/java/ru/yandex/practicum/filmorate/validator/LegalFilmDate.java
similarity index 92%
rename from src/main/java/ru/yandex/practicum/filmorate/model/LegalFilmDate.java
rename to src/main/java/ru/yandex/practicum/filmorate/validator/LegalFilmDate.java
index 6a48a1c..d0d9105 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/LegalFilmDate.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/validator/LegalFilmDate.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.filmorate.model;
+package ru.yandex.practicum.filmorate.validator;
import jakarta.validation.Constraint;
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/LegalFilmDateValidator.java b/src/main/java/ru/yandex/practicum/filmorate/validator/LegalFilmDateValidator.java
similarity index 94%
rename from src/main/java/ru/yandex/practicum/filmorate/model/LegalFilmDateValidator.java
rename to src/main/java/ru/yandex/practicum/filmorate/validator/LegalFilmDateValidator.java
index 23eae05..99b44b3 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/LegalFilmDateValidator.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/validator/LegalFilmDateValidator.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.filmorate.model;
+package ru.yandex.practicum.filmorate.validator;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/LocalDateAdapter.java b/src/main/java/ru/yandex/practicum/filmorate/validator/LocalDateAdapter.java
similarity index 95%
rename from src/main/java/ru/yandex/practicum/filmorate/model/LocalDateAdapter.java
rename to src/main/java/ru/yandex/practicum/filmorate/validator/LocalDateAdapter.java
index 3722b3c..6f015e2 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/LocalDateAdapter.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/validator/LocalDateAdapter.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.filmorate.model;
+package ru.yandex.practicum.filmorate.validator;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Marker.java b/src/main/java/ru/yandex/practicum/filmorate/validator/Marker.java
similarity index 87%
rename from src/main/java/ru/yandex/practicum/filmorate/model/Marker.java
rename to src/main/java/ru/yandex/practicum/filmorate/validator/Marker.java
index e595677..665d46f 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/Marker.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/validator/Marker.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.filmorate.model;
+package ru.yandex.practicum.filmorate.validator;
/**
* Описание интерфейсов групп проверки аннотаций
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/ValidationErrorResponse.java b/src/main/java/ru/yandex/practicum/filmorate/validator/ValidationErrorResponse.java
similarity index 90%
rename from src/main/java/ru/yandex/practicum/filmorate/model/ValidationErrorResponse.java
rename to src/main/java/ru/yandex/practicum/filmorate/validator/ValidationErrorResponse.java
index 08d0619..42e9cf7 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/ValidationErrorResponse.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/validator/ValidationErrorResponse.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.filmorate.model;
+package ru.yandex.practicum.filmorate.validator;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
diff --git a/src/main/java/ru/yandex/practicum/filmorate/model/Violation.java b/src/main/java/ru/yandex/practicum/filmorate/validator/Violation.java
similarity index 88%
rename from src/main/java/ru/yandex/practicum/filmorate/model/Violation.java
rename to src/main/java/ru/yandex/practicum/filmorate/validator/Violation.java
index e28b642..68db96c 100644
--- a/src/main/java/ru/yandex/practicum/filmorate/model/Violation.java
+++ b/src/main/java/ru/yandex/practicum/filmorate/validator/Violation.java
@@ -1,4 +1,4 @@
-package ru.yandex.practicum.filmorate.model;
+package ru.yandex.practicum.filmorate.validator;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 28aacc1..aa40b46 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,4 +1,8 @@
-server.port=8080
+spring.sql.init.mode=always
+spring.datasource.url=jdbc:h2:mem:filmorate
+spring.datasource.driverClassName=org.h2.Driver
+spring.datasource.username=sa
+spring.datasource.password=password
+server.port=8080
logging.level.org.zalando.logbook: TRACE
-
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
new file mode 100644
index 0000000..4af8e5e
--- /dev/null
+++ b/src/main/resources/data.sql
@@ -0,0 +1,17 @@
+-- Заполняем справочник жанров
+MERGE INTO genres (id, name)
+ VALUES ( 1, 'Комедия'),
+ (2, 'Драма'),
+ (3, 'Мультфильм'),
+ (4, 'Триллер'),
+ (5, 'Документальный'),
+ (6, 'Боевик');
+
+-- Заполняем справочник рейтингов MPA
+MERGE INTO MPA (id, name, description)
+ VALUES (1, 'G', 'у фильма нет возрастных ограничений'),
+ (2, 'PG', 'детям рекомендуется смотреть фильм с родителями'),
+ (3, 'PG-13', 'детям до 13 лет просмотр не желателен'),
+ (4, 'R', 'лицам до 17 лет просматривать фильм можно только в присутствии взрослого'),
+ (5, 'NC-17', 'лицам до 18 лет просмотр запрещён');
+
diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql
new file mode 100644
index 0000000..a6d0924
--- /dev/null
+++ b/src/main/resources/schema.sql
@@ -0,0 +1,53 @@
+-- Создаем таблицу пользователей
+CREATE TABLE IF NOT EXISTS users (
+ id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
+ email VARCHAR(255) UNIQUE NOT NULL,
+ login VARCHAR(40) NOT NULL,
+ name VARCHAR(40) NOT NULL,
+ birthday DATE NOT NULL
+);
+
+-- Создаем таблицу друзей
+CREATE TABLE IF NOT EXISTS friends (
+ user_id INTEGER NOT NULL REFERENCES users(id),
+ friend_id INTEGER NOT NULL REFERENCES users(id),
+ confirmed BOOLEAN NOT NULL DEFAULT FALSE,
+ PRIMARY KEY (user_id, friend_id)
+);
+
+-- Создаем справочник жанров фильма
+CREATE TABLE IF NOT EXISTS genres (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(40) NOT NULL
+);
+
+-- Создаем справочник рейтинга MPA
+CREATE TABLE IF NOT EXISTS MPA (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(8) NOT NULL,
+ description VARCHAR(80)
+);
+
+-- Создаем таблицу описания фильма
+CREATE TABLE IF NOT EXISTS films (
+ id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
+ name VARCHAR(40) NOT NULL,
+ description VARCHAR(200),
+ releaseDate DATE,
+ len_min INTEGER,
+ MPA_id INTEGER NOT NULL REFERENCES MPA(id)
+);
+
+-- Создаем таблицу описания жанра фильма
+CREATE TABLE IF NOT EXISTS films_genres (
+ film_id INTEGER NOT NULL REFERENCES films(id),
+ genre_id INTEGER NOT NULL REFERENCES genres(id),
+ PRIMARY KEY (film_id, genre_id)
+);
+
+-- Создаем таблицу "лайков" к фильмам
+CREATE TABLE IF NOT EXISTS likes (
+ user_id INTEGER NOT NULL REFERENCES users(id),
+ film_id INTEGER NOT NULL REFERENCES films(id),
+ PRIMARY KEY (user_id, film_id)
+);
diff --git a/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java b/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java
index 660412e..02f0bf6 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/FilmorateApplicationTests.java
@@ -1,13 +1,13 @@
package ru.yandex.practicum.filmorate;
import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
+@AutoConfigureTestDatabase
class FilmorateApplicationTests {
-
- @Test
- void contextLoads() {
- }
-
+ @Test
+ void contextLoads() throws Exception {
+ }
}
diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java
index cc3de5e..2b24a07 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/controller/FilmControllerTest.java
@@ -2,67 +2,106 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
-import org.junit.jupiter.api.BeforeEach;
+import com.google.gson.reflect.TypeToken;
+import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
import ru.yandex.practicum.filmorate.model.Film;
-import ru.yandex.practicum.filmorate.model.LocalDateAdapter;
-import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.model.Genre;
+import ru.yandex.practicum.filmorate.model.Mpa;
+import ru.yandex.practicum.filmorate.validator.LocalDateAdapter;
import java.time.LocalDate;
+import java.util.List;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
- * Тестируем контроллер запросов о фильмах
+ * Тестируем контроллер запросов работы с данными о фильмах
+ *
+ * Для успешного выполнения тестов, при инициализации базы данных
+ * должна быть подготовлена информация о четырех тестовых фильмах и
+ * о четырех тестовых пользователях.
+ * Файл первоначальных данных ./src/test/resources/data.sql
*/
@SpringBootTest
@AutoConfigureMockMvc
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
class FilmControllerTest {
+ private static final int TEST_FILM_ID = 1;
+
@Autowired
MockMvc mvc;
- static Gson gson = new GsonBuilder()
+ Gson gson = new GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(LocalDate.class, new LocalDateAdapter())
.create();
+ // Определяем тип сериализации списка
+ class FilmListTypeToken extends TypeToken> {
+ }
+
/**
- * Перед каждым тестом очищаем список фильмов.
+ * Генерация информации о тестовом фильме
+ * Поля должны соответствовать содержимому базы данных для фильма TEST_FILM_ID
+ *
+ * @return - объект, который ожидается для TEST_FILM_ID
*/
- @BeforeEach
- void setUp() throws Exception {
- mvc.perform(delete("/films"))
- .andExpect(status().isOk());
-
- mvc.perform(delete("/users"))
- .andExpect(status().isOk());
-
- // Создадим одного пользователя для "лайков"
- User user = new User("User1234@domain",
- "user1234", "test user",
- LocalDate.now().minusYears(22));
-
- String jsonString = gson.toJson(user);
- mvc.perform(post("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isCreated());
+ static Film getTestFilm() {
+ Film film = new Film();
+ film.setId(TEST_FILM_ID);
+ film.setName("TestFilmName");
+ film.setDescription("TestFilmDescription");
+ film.setReleaseDate(LocalDate.of(2001, 2, 3));
+ film.setDuration(51);
+ film.setMpa(new Mpa(1));
+ film.addGenre(new Genre(1, "Комедия"));
+ return film;
}
/**
- * Тестируем режим поиска фильмов.
+ * Тестируем поиск всех фильмов
*/
@Test
void findAllFilms() throws Exception {
- makeFilms(3);
- mvc.perform(get("/films"))
- .andExpect(status().isOk());
+ MvcResult result = mvc.perform(get("/films"))
+ .andExpect(status().isOk()) // ожидается код статус 200
+ .andReturn();
+ List films = gson.fromJson(result.getResponse().getContentAsString(),
+ new FilmListTypeToken().getType());
+ assertTrue(!films.isEmpty(),
+ "Список фильмов пуст.");
+ }
+
+ /**
+ * Тестируем поиск фильма по идентификатору
+ */
+ @Test
+ void findFilm() throws Exception {
+ // попытка поиска несуществующего фильма
+ mvc.perform(get("/films/10000"))
+ .andExpect(status().isNotFound()); // ожидается код статус 404
+
+ // поиск тестового фильма
+ MvcResult result = mvc.perform(get("/films/" + TEST_FILM_ID))
+ .andExpect(status().isOk()) // ожидается код статус 200
+ .andReturn();
+ Film filmDb = gson.fromJson(result.getResponse().getContentAsString(), Film.class);
+ assertThat(filmDb)
+ .withFailMessage("Считанный объект не соответствует ожидаемому.")
+ .isEqualTo(getTestFilm());
}
/**
@@ -70,25 +109,21 @@ void findAllFilms() throws Exception {
*/
@Test
void addNewFilm() throws Exception {
- Film film = new Film("Film Test1",
- "Testing addNewFilm",
- LocalDate.now().minusYears(10),
- 60, 0);
+ Film film = getTestFilm();
+ film.setId(null);
+ film.setName("NewTestFilm");
String jsonString = gson.toJson(film);
// При успешном добавлении фильма
- // должен возвращаться статус 200 "Ok"
- mvc.perform(post("/films")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isCreated());
-
- // При повторном добавлении фильма
- // должен возвращаться статус 400 "BadRequest"
- mvc.perform(post("/films")
+ // должен возвращаться статус 201 "Created"
+ MvcResult result = mvc.perform(post("/films")
.content(jsonString)
.contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest());
+ .andExpect(status().isCreated())
+ .andReturn();
+ Film filmDb = gson.fromJson(result.getResponse().getContentAsString(), Film.class);
+ assertNotNull(filmDb.getId(),
+ "при добавлении фильма должен присваиваться ненулевой идентификатор.");
}
/**
@@ -96,19 +131,26 @@ void addNewFilm() throws Exception {
*/
@Test
void updateFilm() throws Exception {
- Film film = new Film("Film Test2",
- "Testing updateFilm",
- LocalDate.now().minusYears(10),
- 60, 0);
+ Film film = getTestFilm();
+ film.setId(null);
+ film.setName("TestFilmForUpdate");
String jsonString = gson.toJson(film);
- // Добавляем тестовый фильм
- mvc.perform(post("/films")
+ // При успешном добавлении фильма
+ // должен возвращаться статус 201 "Created"
+ MvcResult result = mvc.perform(post("/films")
.content(jsonString)
.contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isCreated());
+ .andExpect(status().isCreated())
+ .andReturn();
+ Film filmDb = gson.fromJson(result.getResponse().getContentAsString(), Film.class);
+
+ // Готовим информацию для обновления
+ film.setName("TestFilmNameUpdated");
+ film.setDescription("Description updated");
+ film.addGenre(new Genre(3, "Мультфильм"));
+ jsonString = gson.toJson(film);
- film.setDescription("Updated.");
jsonString = gson.toJson(film);
// При обновлении фильма с отсутствующим id
// должен возвращаться статус 400 "BadRequest"
@@ -117,7 +159,6 @@ void updateFilm() throws Exception {
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest());
-
film.setId(1000);
jsonString = gson.toJson(film);
// При обновлении фильма с неверным id
@@ -127,14 +168,19 @@ void updateFilm() throws Exception {
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound());
- film.setId(1);
+ film.setId(filmDb.getId());
jsonString = gson.toJson(film);
// При обновлении фильма с корректным id
// должен возвращаться статус 200 "Ok"
- mvc.perform(put("/films")
+ result = mvc.perform(put("/films")
.content(jsonString)
.contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk());
+ .andExpect(status().isOk())
+ .andReturn();
+ filmDb = gson.fromJson(result.getResponse().getContentAsString(), Film.class);
+ assertThat(filmDb)
+ .withFailMessage("Обновленный объект не соответствует ожидаемому.")
+ .isEqualTo(film);
}
/**
@@ -144,61 +190,53 @@ void updateFilm() throws Exception {
*/
@Test
void addLike() throws Exception {
- makeFilms(3);
-
// При добавлении "лайка" от несуществующего пользователя
// должен возвращаться статус 404 "NotFound"
mvc.perform(put("/films/1/like/1000")
- .content("")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound());
// При добавлении "лайка"
// должен возвращаться статус 200 "Ok"
- mvc.perform(put("/films/2/like/1")
- .content("")
+ mvc.perform(put("/films/1/like/1")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
/**
* Тестируем удаление "лайка"
- *
- * @throws Exception
*/
@Test
- void deleteLike() throws Exception {
+ void removeLike() throws Exception {
addLike();
// При удалении "лайка"
// должен возвращаться статус 200 "Ok"
- mvc.perform(delete("/films/2/like/1")
- .content("")
+ mvc.perform(delete("/films/1/like/1")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
- /**
- * Генерация тестовых фильмов
- *
- * @param count - количество фильмов
- * @throws Exception
- */
- void makeFilms(int count) throws Exception {
- StringBuilder fBuilder = new StringBuilder();
- fBuilder.append("{\"name\": \"Film%d\",");
- fBuilder.append("\"description\": \"description%d\",");
- fBuilder.append("\"releaseDate\": \"2000-01-%02d\",");
- fBuilder.append("\"duration\": %d}");
- String formatStr = fBuilder.toString();
-
- for (int i = 1; i <= count; i++) {
- String jsonString = String.format(formatStr, i, i, i, i * 10);
- mvc.perform(post("/films")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isCreated());
- }
-
+ @Test
+ void findPopularFilms() throws Exception {
+ mvc.perform(put("/films/1/like/1").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
+ mvc.perform(put("/films/2/like/1").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
+ mvc.perform(put("/films/2/like/2").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
+ mvc.perform(put("/films/3/like/1").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
+ mvc.perform(put("/films/3/like/3").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
+ mvc.perform(put("/films/3/like/2").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
+ mvc.perform(put("/films/3/like/4").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
+ mvc.perform(put("/films/4/like/2").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
+ mvc.perform(put("/films/4/like/3").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
+ mvc.perform(put("/films/4/like/3").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
+
+ MvcResult result = mvc.perform(get("/films/popular?count=2"))
+ .andExpect(status().isOk()) // ожидается код статус 200
+ .andReturn();
+ List filmsPopular = gson.fromJson(result.getResponse().getContentAsString(),
+ new FilmListTypeToken().getType());
+ assertTrue(filmsPopular.size() == 2,
+ "Число популярных фильмов не соответствует ожидаемому");
}
-}
+
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/GenreControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/GenreControllerTest.java
new file mode 100644
index 0000000..84245c1
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/controller/GenreControllerTest.java
@@ -0,0 +1,94 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import ru.yandex.practicum.filmorate.model.Genre;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ * Тестирование контроллера запросов работы со справочником жанров фильа
+ *
+ * Для успешного выполнения тестов, при инициализации базы данных
+ * должндолжен быть полностью заполнен справочник жанров.
+ * Файл первоначальных данных ./src/test/resources/data.sql
+ */
+@SpringBootTest
+@AutoConfigureMockMvc
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+class GenreControllerTest {
+
+ private static final List testGenres = new ArrayList<>();
+
+ @Autowired
+ MockMvc mvc;
+
+ // Определяем тип сериализации списка
+ class GenreListTypeToken extends TypeToken> {
+ }
+
+ Gson gson = new GsonBuilder()
+ .setPrettyPrinting()
+ .create();
+
+ /**
+ * Инициализация эталонного списка жанров.
+ */
+ @BeforeAll
+ static void setUp() {
+ testGenres.add(new Genre(1, "Комедия"));
+ testGenres.add(new Genre(2, "Драма"));
+ testGenres.add(new Genre(3, "Мультфильм"));
+ testGenres.add(new Genre(4, "Триллер"));
+ testGenres.add(new Genre(5, "Документальный"));
+ testGenres.add(new Genre(6, "Боевик"));
+ }
+
+ /**
+ * Тестируем список всех жанров
+ */
+ @Test
+ void findAllGenres() throws Exception {
+ MvcResult result = mvc.perform(get("/genres"))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ List genres = gson.fromJson(result.getResponse().getContentAsString(),
+ new GenreListTypeToken().getType());
+ for (Genre genre : genres) {
+ assertTrue(testGenres.contains(genre),
+ "Получен неизвестный жанр: " + genre.toString());
+ }
+ }
+
+ /**
+ * Тестируем поиск жанра по идентификатору
+ */
+ @Test
+ void findGenreById() throws Exception {
+ for (Genre genre : testGenres) {
+ MvcResult result = mvc.perform(get("/genres/" + genre.getId()))
+ .andExpect(status().isOk())
+ .andReturn();
+ Genre genreDb = gson.fromJson(result.getResponse().getContentAsString(), Genre.class);
+ assertTrue(genre.equals(genreDb),
+ "Получен неизвестный жанр: " + genreDb.toString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/MpaControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/MpaControllerTest.java
new file mode 100644
index 0000000..602f723
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/controller/MpaControllerTest.java
@@ -0,0 +1,98 @@
+package ru.yandex.practicum.filmorate.controller;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import ru.yandex.practicum.filmorate.model.Genre;
+import ru.yandex.practicum.filmorate.model.Mpa;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+/**
+ * Тестирование контроллера запросов работы со справочником жанров рейтингов MPA
+ *
+ * Для успешного выполнения тестов, при инициализации базы данных
+ * должндолжен быть полностью заполнен справочник рейтингов.
+ * Файл первоначальных данных ./src/test/resources/data.sql
+ */
+@SpringBootTest
+@AutoConfigureMockMvc
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+class MpaControllerTest {
+ private static List testMpaList = new ArrayList<>();
+
+ private static final List testGenres = new ArrayList<>();
+
+ @Autowired
+ MockMvc mvc;
+
+ // Определяем тип сериализации списка
+ class MpaListTypeToken extends TypeToken> {
+ }
+
+ Gson gson = new GsonBuilder()
+ .setPrettyPrinting()
+ .create();
+
+ /**
+ * Инициализация эталонного списка рейтингов.
+ */
+ @BeforeAll
+ static void setUp() {
+ testMpaList.add(new Mpa(1, "G", "у фильма нет возрастных ограничений"));
+ testMpaList.add(new Mpa(2, "PG", "детям рекомендуется смотреть фильм с родителями"));
+ testMpaList.add(new Mpa(3, "PG-13", "детям до 13 лет просмотр не желателен"));
+ testMpaList.add(new Mpa(4, "R", "лицам до 17 лет просматривать фильм можно только в присутствии взрослого"));
+ testMpaList.add(new Mpa(5, "NC-17", "лицам до 18 лет просмотр запрещён"));
+ }
+
+ /**
+ * Тестируем список всех рейтингов
+ */
+ @Test
+ void findAllMpa() throws Exception {
+ MvcResult result = mvc.perform(get("/mpa"))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ List mpas = gson.fromJson(result.getResponse().getContentAsString(),
+ new MpaListTypeToken().getType());
+ for (Mpa mpa : mpas) {
+ assertTrue(testMpaList.contains(mpa),
+ "Получен неизвестный рейтинг: " + mpa.toString());
+ }
+ }
+
+ /**
+ * Тестируем поиск рейтинга по идентификаторам
+ *
+ * @throws Exception
+ */
+ @Test
+ void findMpaById() throws Exception {
+ for (Mpa mpa : testMpaList) {
+ MvcResult result = mvc.perform(get("/mpa/" + mpa.getId()))
+ .andExpect(status().isOk())
+ .andReturn();
+ Mpa mpaDb = gson.fromJson(result.getResponse().getContentAsString(), Mpa.class);
+ assertTrue(mpa.equals(mpaDb),
+ "Получен неизвестный рейтинг: " + mpaDb.toString());
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java b/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java
index 67c49b1..2ff733b 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/controller/UserControllerTest.java
@@ -2,27 +2,39 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
-import org.junit.jupiter.api.BeforeEach;
+import com.google.gson.reflect.TypeToken;
+import lombok.RequiredArgsConstructor;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
-import ru.yandex.practicum.filmorate.model.LocalDateAdapter;
+import org.springframework.test.web.servlet.MvcResult;
import ru.yandex.practicum.filmorate.model.User;
+import ru.yandex.practicum.filmorate.validator.LocalDateAdapter;
import java.time.LocalDate;
+import java.util.List;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
-import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
- * Тестируем контроллер запросов данных о пользователях
+ * Тестируем контроллер запросов работы с данными о пользователях
+ *
+ * Для успешного выполнения тестов, при инициализации базы данных
+ * должна быть подготовлена информация о четырех тестовых пользователях.
+ * Файл первоначальных данных ./src/test/resources/data.sql
*/
@SpringBootTest
@AutoConfigureMockMvc
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
class UserControllerTest {
@Autowired
MockMvc mvc;
@@ -32,13 +44,8 @@ class UserControllerTest {
.registerTypeAdapter(LocalDate.class, new LocalDateAdapter())
.create();
- /**
- * Перед каждым тестом удаляем всех пользователей
- */
- @BeforeEach
- void setUp() throws Exception {
- mvc.perform(delete("/users"))
- .andExpect(status().isOk());
+ // Определяем тип сериализации списка
+ class UserListTypeToken extends TypeToken> {
}
/**
@@ -46,11 +53,12 @@ void setUp() throws Exception {
*/
@Test
void findAllUser() throws Exception {
- makeUsers(3);
-
- mvc.perform(get("/users"))
- .andExpect(status().isOk()) // ожидается код статус 200
- .andDo(print());
+ MvcResult result = mvc.perform(get("/users"))
+ .andExpect(status().isOk()) // ожидается код статус 200
+ .andReturn();
+ List users = gson.fromJson(result.getResponse().getContentAsString(), new UserListTypeToken().getType());
+ assertTrue(!users.isEmpty(),
+ "Список пользователей пуст.");
}
/**
@@ -58,17 +66,33 @@ void findAllUser() throws Exception {
*/
@Test
void addNewUser() throws Exception {
- User user = new User("User1234@domain",
- "user1234", "test user",
- LocalDate.now().minusYears(22));
+ User user = new User();
+ user.setLogin("user1234");
+ user.setName("testUserName");
+ user.setBirthday(LocalDate.now().minusYears(22));
+
+ user.setEmail("User1234_domain@");
String jsonString = gson.toJson(user);
+ // При добавлении пользователя некорректным Email
+ // должен возвращаться статус 400 "BadRequest"
+ mvc.perform(post("/users")
+ .content(jsonString)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isBadRequest());
+ user.setEmail("User1234@domain");
+ jsonString = gson.toJson(user);
// При успешном добавлении пользователя
- // должен возвращаться статус 200 "Ok"
- mvc.perform(post("/users")
+ // должен возвращаться статус 201 "Created"
+ MvcResult result = mvc.perform(post("/users")
.content(jsonString)
.contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isCreated());
+ .andExpect(status().isCreated())
+ .andReturn();
+ // Сохраняем созданного пользователя
+ User userDb = gson.fromJson(result.getResponse().getContentAsString(), User.class);
+ assertNotNull(userDb.getId(),
+ "При добавлении пользователя должен быть присвоен ненулевой идентификатор");
// Повторное добавление пользователя
// должно возвращать статус 400 "BadRequest"
@@ -83,22 +107,30 @@ void addNewUser() throws Exception {
*/
@Test
void updateUser() throws Exception {
- User user = new User("User1234@domain",
- "user0000", "testing user",
- LocalDate.now().minusYears(22));
+ User user = new User();
+ user.setEmail("UserUpdate@domain");
+ user.setLogin("userUpdate");
+ user.setName("testUpdateUserName");
+ user.setBirthday(LocalDate.now().minusYears(22));
String jsonString = gson.toJson(user);
- // Создаем тестового пользователя
- mvc.perform(post("/users")
+ // При успешном добавлении пользователя
+ // должен возвращаться статус 201 "Created"
+ MvcResult result = mvc.perform(post("/users")
.content(jsonString)
.contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isCreated());
+ .andExpect(status().isCreated())
+ .andReturn();
+ // Сохраняем созданного пользователя
+ User userDb = gson.fromJson(result.getResponse().getContentAsString(), User.class);
- user.setLogin("user12345");
+ // готовим данные для обновления
+ user.setLogin("userUpd12345");
user.setName("Updated user.");
- jsonString = gson.toJson(user);
+ user.setBirthday(LocalDate.now().minusYears(22));
- // Обновление записи без идентификатора
+ jsonString = gson.toJson(user);
+ // Обновление записи без идентификатора пользователя
// должно возвращать статус 400 "BadRequest"
mvc.perform(put("/users")
.content(jsonString)
@@ -114,170 +146,155 @@ void updateUser() throws Exception {
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound());
- user.setId(1);
+ user.setId(userDb.getId());
jsonString = gson.toJson(user);
// Успешное обновление записи
// должно возвращать статус 200 "Ok"
- mvc.perform(put("/users")
+ result = mvc.perform(put("/users")
.content(jsonString)
.contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk());
+ .andExpect(status().isOk())
+ .andReturn();
+ // Сохраняем пользователя из ответа после обновления
+ userDb = gson.fromJson(result.getResponse().getContentAsString(), User.class);
+
+ assertThat(userDb)
+ .usingRecursiveComparison()
+ .isEqualTo(user);
}
/**
- * Тестируем добавление друзей
+ * Тестирование добавления "друга"
*
* @throws Exception
*/
@Test
void addFriends() throws Exception {
- makeUsers(3);
-
// Объявление в "друзья" несуществующего пользователя
// должно возвращать статус 404 "NotFound"
mvc.perform(put("/users/1000/friends/1")
- .content("")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound());
// Объявление в "друзья" несуществующего друга
// должно возвращать статус 404 "NotFound()"
mvc.perform(put("/users/1/friends/1000")
- .content("")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound());
// Объявление в "друзья" сущществующих пользователей
// должно возвращать статус 200 "ok"
mvc.perform(put("/users/1/friends/2")
- .content("")
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk());
-
- // Объявление в "друзья" сущществующих пользователей (граничный случай)
- // должно возвращать статус 200 "ok"
- mvc.perform(put("/users/3/friends/2")
- .content("")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
/**
- * Тестируем удаление друзей
+ * Тестирование удаления пользователя из друзей
*
* @throws Exception
*/
@Test
- void removeFriends() throws Exception {
- addFriends();
+ void breakUpFriends() throws Exception {
+ // Добавление в "друзья" пользователея
+ // должно возвращать статус 200 "ok"
+ mvc.perform(put("/users/1/friends/2")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
// Удаление из "друзьей" не сущществующих пользователей
// должно возвращать статус 404 "NotFound"
mvc.perform(delete("/users/1/friends/1000")
- .content("")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound());
// Удаление из "друзьей" сущществующих пользователей
// должно возвращать статус 200 "Ok"
mvc.perform(delete("/users/1/friends/2")
- .content("")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
/**
- * Тестируем чтение списка друзей
+ * Тестирование поиска друзей пользователя
*
* @throws Exception
*/
@Test
- void getFriends() throws Exception {
- makeUsers(3);
-
- // Объявление в "друзья"
+ void findUsersFriends() throws Exception {
+ // Добавление в "друзья" пользователея
// должно возвращать статус 200 "ok"
- mvc.perform(put("/users/1/friends/2")
- .content("")
+ mvc.perform(put("/users/4/friends/2")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
- // Объявление в "друзья"
+ // Добавление в "друзья" пользователея
// должно возвращать статус 200 "ok"
- mvc.perform(put("/users/3/friends/2")
- .content("")
+ mvc.perform(put("/users/4/friends/3")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
// читаем список "друзей", несуществующего пользователя
// должно возвращать статус 404 "NotFound"
mvc.perform(get("/users/2000/friends")
- .content("")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound());
-
// читаем список "друзей"
// должно возвращать статус 200 "ok"
- mvc.perform(get("/users/2/friends")
- .content("")
+ MvcResult result = mvc.perform(get("/users/4/friends")
.contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk());
+ .andExpect(status().isOk())
+ .andReturn();
+ List users = gson.fromJson(result.getResponse().getContentAsString(), new UserListTypeToken().getType());
+ assertTrue(users.size() == 2,
+ "Количество найденых \"друзей\" не соответствует ожидаемому.");
}
/**
- * Тестируем поиск общих друзей
+ * Тестирование поиска общих друзей у пользователей
*
* @throws Exception
*/
@Test
- void findCommonFrends() throws Exception {
- makeUsers(3);
-
- // Объявление в "друзья"
- // должно возвращать статус 200 "ok"
+ void findCommonFriends() throws Exception {
mvc.perform(put("/users/1/friends/2")
- .content("")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
- // Объявление в "друзья"
- // должно возвращать статус 200 "ok"
+ mvc.perform(put("/users/1/friends/3")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+
+ mvc.perform(put("/users/1/friends/4")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+
mvc.perform(put("/users/3/friends/2")
- .content("")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+
+ mvc.perform(put("/users/3/friends/1")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+
+ mvc.perform(put("/users/4/friends/2")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk());
+
+ mvc.perform(put("/users/4/friends/3")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
// читаем список общих "друзей"
// должно возвращать статус 200 "ok"
- mvc.perform(get("/users/1/friends/common/3")
- .content("")
+ MvcResult result = mvc.perform(get("/users/1/friends/common/4")
.contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk());
+ .andExpect(status().isOk())
+ .andReturn();
+ List users = gson.fromJson(result.getResponse().getContentAsString(), new UserListTypeToken().getType());
+ assertTrue(users.size() == 2,
+ "Количество общих \"друзей\" не соответствует ожидаемому.");
}
- /**
- * Создание тестовых пользователей
- *
- * @param count - требуемое клличество тестовых пользователей
- * @throws Exception
- */
- void makeUsers(int count) throws Exception {
- StringBuilder fBuilder = new StringBuilder();
- fBuilder.append("{\"email\": \"user000%d@domain\",");
- fBuilder.append("\"login\": \"USER000%d\",");
- fBuilder.append("\"name\": \"userName00%d\",");
- fBuilder.append("\"birthday\": \"2000-01-%02d\"}");
- String formatStr = fBuilder.toString();
-
- for (int i = 1; i <= count; i++) {
- String jsonString = String.format(formatStr, i, i, i, i);
- // При успешном добавлении пользователя
- // должен возвращаться статус 200 "Ok"
- mvc.perform(post("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isCreated());
- }
- }
-}
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/model/FilmApiTest.java b/src/test/java/ru/yandex/practicum/filmorate/model/FilmApiTest.java
deleted file mode 100644
index a72aa0e..0000000
--- a/src/test/java/ru/yandex/practicum/filmorate/model/FilmApiTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-package ru.yandex.practicum.filmorate.model;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.MediaType;
-import org.springframework.test.web.servlet.MockMvc;
-
-import java.time.LocalDate;
-
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
-import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-/**
- * Тестирование ограничений на значения полей класса Film при Http запросах
- * Тестирование использования объектов в качестве параметров методов
- */
-@SpringBootTest
-@AutoConfigureMockMvc
-class FilmApiTest {
- @Autowired
- private MockMvc mvc;
-
- private Gson gson = new GsonBuilder()
- .setPrettyPrinting()
- .registerTypeAdapter(LocalDate.class, new LocalDateAdapter())
- .create();
-
- /**
- * Перед каждым тестом очищаем список фильмов.
- */
- @BeforeEach
- void setUp() throws Exception {
- mvc.perform(delete("/films"))
- .andExpect(status().isOk());
- }
-
- /**
- * Проверка непустого названия фильма.
- */
- @Test
- void testName() throws Exception {
- Film film = new Film("",
- "Testing film.name",
- LocalDate.now().minusYears(10),
- 60, 0);
- String jsonString = gson.toJson(film);
- // При добавлении фильма без названия
- // должен возвращаться статус 400 "BadRequest"
- mvc.perform(post("/films")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest())
- .andDo(print());
- }
-
- /**
- * Проверка допусимого размера описания.
- */
- @Test
- void testDescription() throws Exception {
- Film film = new Film("Film",
- "12345678901234567890123456789012345678901234567890"
- + "12345678901234567890123456789012345678901234567890"
- + "12345678901234567890123456789012345678901234567890"
- + "12345678901234567890123456789012345678901234567890"
- + "12345678901234567890123456789012345678901234567890",
- LocalDate.now().minusYears(10),
- 60, 0);
- String jsonString = gson.toJson(film);
- // При добавлении фильма
- // должен возвращаться статус 400 "BadRequest"
- mvc.perform(post("/films")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest())
- .andDo(print());
-
- }
-
- /**
- * Проверка допустимой даты выпуска фильма
- */
- @Test
- void testReleaseDate() throws Exception {
- Film film = new Film("Film",
- "Testing film.releaseDate",
- LocalDate.now().plusDays(1),
- 60, 0);
- String jsonString = gson.toJson(film);
- // При добавлении фильма
- // должен возвращаться статус 400 "BadRequest"
- mvc.perform(post("/films")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest())
- .andDo(print());
-
- film.setReleaseDate(LocalDate.of(1895, 12, 27));
- jsonString = gson.toJson(film);
- // При добавлении фильма
- // должен возвращаться статус 400 "BadRequest"
- mvc.perform(post("/films")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest())
- .andDo(print());
- }
-
- /**
- * Проверка допустимой длительности фильма
- */
- @Test
- void testDuration() throws Exception {
- Film film = new Film("Film",
- "Testing film.releaseDate",
- LocalDate.now().minusYears(10),
- 0, 0);
- String jsonString = gson.toJson(film);
-
- // При добавлении фильма
- // должен возвращаться статус 400 "BadRequest"
- mvc.perform(post("/films")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest())
- .andDo(print());
- }
-
-}
diff --git a/src/test/java/ru/yandex/practicum/filmorate/model/FilmTest.java b/src/test/java/ru/yandex/practicum/filmorate/model/FilmTest.java
index f5da073..621ab84 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/model/FilmTest.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/model/FilmTest.java
@@ -1,3 +1,4 @@
+
package ru.yandex.practicum.filmorate.model;
import jakarta.validation.ConstraintViolation;
@@ -6,6 +7,7 @@
import jakarta.validation.ValidatorFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import ru.yandex.practicum.filmorate.validator.Marker;
import java.time.LocalDate;
import java.util.Set;
@@ -15,7 +17,6 @@
/**
* Тестирование ограничений на значения полей класса Film
- * Автономный тест (Junit).
*/
class FilmTest {
private Validator validator;
@@ -34,10 +35,12 @@ void setUp() {
*/
@Test
void testName() {
- Film film = new Film("",
- "Testing film.name",
- LocalDate.now().minusYears(10),
- 60, 0);
+ Film film = new Film();
+ film.setName("");
+ film.setDescription("Testing film");
+ film.setReleaseDate(LocalDate.now().minusYears(10));
+ film.setDuration(60);
+ film.setMpa(new Mpa(1));
Set> violations = validator.validate(film, Marker.OnBasic.class);
assertFalse(violations.isEmpty());
@@ -48,14 +51,16 @@ void testName() {
*/
@Test
void testDescription() {
- Film film = new Film("Film",
- "12345678901234567890123456789012345678901234567890"
- + "12345678901234567890123456789012345678901234567890"
- + "12345678901234567890123456789012345678901234567890"
- + "12345678901234567890123456789012345678901234567890"
- + "12345678901234567890123456789012345678901234567890",
- LocalDate.now().minusYears(10),
- 60, 0);
+ Film film = new Film();
+ film.setName("Film");
+ film.setDescription("12345678901234567890123456789012345678901234567890"
+ + "12345678901234567890123456789012345678901234567890"
+ + "12345678901234567890123456789012345678901234567890"
+ + "12345678901234567890123456789012345678901234567890"
+ + "12345678901234567890123456789012345678901234567890");
+ film.setReleaseDate(LocalDate.now().minusYears(10));
+ film.setDuration(60);
+ film.setMpa(new Mpa(1));
Set> violations = validator.validate(film, Marker.OnBasic.class);
assertFalse(violations.isEmpty());
@@ -66,14 +71,18 @@ void testDescription() {
*/
@Test
void testReleaseDate() {
- Film film = new Film("Film",
- "Testing film.releaseDate",
- LocalDate.now().plusDays(1),
- 60, 0);
-
+ Film film = new Film();
+ film.setName("Film");
+ film.setDescription("Testing film ReleaseDate");
+ film.setReleaseDate(LocalDate.now().plusDays(1));
+ film.setDuration(60);
+ film.setMpa(new Mpa(1));
+
+ // Проверяем на контроль даты в будущем
Set> violations = validator.validate(film, Marker.OnBasic.class);
assertFalse(violations.isEmpty());
+ // Проверяем на контроль минимальной даты выхода фильма
film.setReleaseDate(LocalDate.of(1895, 12, 27));
violations.clear();
@@ -86,10 +95,12 @@ void testReleaseDate() {
*/
@Test
void testDuration() {
- Film film = new Film("Film",
- "Testing film.duration",
- LocalDate.now().minusYears(10),
- 0, 0);
+ Film film = new Film();
+ film.setName("Film");
+ film.setDescription("Testing film ReleaseDate");
+ film.setReleaseDate(LocalDate.now().minusYears(10));
+ film.setDuration(0);
+ film.setMpa(new Mpa(1));
Set> violations = validator.validate(film, Marker.OnBasic.class);
assertFalse(violations.isEmpty());
@@ -100,13 +111,15 @@ void testDuration() {
*/
@Test
void testFilmOk() {
- Film film = new Film("Film Ok",
- "Testing film",
- LocalDate.now().minusYears(10),
- 60, 0);
+ Film film = new Film();
+ film.setName("Film");
+ film.setDescription("Testing film ReleaseDate");
+ film.setReleaseDate(LocalDate.now().minusYears(10));
+ film.setDuration(60);
+ film.setMpa(new Mpa(1));
Set> violations = validator.validate(film, Marker.OnBasic.class);
assertTrue(violations.isEmpty(), violations.toString());
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/ru/yandex/practicum/filmorate/model/UserApiTest.java b/src/test/java/ru/yandex/practicum/filmorate/model/UserApiTest.java
deleted file mode 100644
index f14854a..0000000
--- a/src/test/java/ru/yandex/practicum/filmorate/model/UserApiTest.java
+++ /dev/null
@@ -1,209 +0,0 @@
-package ru.yandex.practicum.filmorate.model;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.MediaType;
-import org.springframework.test.web.servlet.MockMvc;
-
-import java.time.LocalDate;
-
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-/**
- * Тестирование ограничений на значения класса User при Http запросах.
- * Тестирование использования объектов в качестве параметров методов
- */
-@SpringBootTest
-@AutoConfigureMockMvc
-class UserApiTest {
- @Autowired
- private MockMvc mvc;
-
- private Gson gson = new GsonBuilder()
- .setPrettyPrinting()
- .registerTypeAdapter(LocalDate.class, new LocalDateAdapter())
- .create();
-
- /**
- * Перед каждым тестом удаляем всех пользователей
- */
- @BeforeEach
- void setUp(/*@Autowired MockMvc mvc*/) throws Exception {
- mvc.perform(delete("/users"))
- .andExpect(status().isOk());
- }
-
- /**
- * Тестирование email пользователя
- */
- @Test
- void testEmail() throws Exception {
- User user = new User(null,
- "userTest",
- "Testing user",
- LocalDate.now().minusYears(32));
- String jsonString = gson.toJson(user);
-
- // Создание пользователя без email
- // должно возвращать статус 400 "BadRequest"
- mvc.perform(post("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest());
-
- user.setEmail("user.domain@");
- jsonString = gson.toJson(user);
- // Создание пользователя с неправильным email
- // должно возвращать статус 400 "BadRequest"
- mvc.perform(post("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest());
-
- user.setEmail("user@domain");
- jsonString = gson.toJson(user);
- // Создание пользователя с корректным email
- // должно возвращать статус 201 "Created"
- mvc.perform(post("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isCreated());
- }
-
- /**
- * Тестирование login пользователя
- */
- @Test
- void testLogin() throws Exception {
- User user = new User("user1234@test",
- "",
- "Testing user",
- LocalDate.now().minusYears(32));
- String jsonString = gson.toJson(user);
-
- // Создание пользователя с пустым login
- // должно возвращать статус 400 "BadRequest"
- mvc.perform(post("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest());
-
- user.setLogin("user test");
- jsonString = gson.toJson(user);
- // Создание пользователя с login содержащим пробел
- // должно возвращать статус 400 "BadRequest"
- mvc.perform(post("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest());
-
- user.setLogin("user1234");
- jsonString = gson.toJson(user);
- // Создание пользователя с корректным login (содержит только латинские буквы и цифры)
- // должно возвращать статус 201 "Created"
- mvc.perform(post("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isCreated());
- }
-
- /**
- * Тестируем корректность даты рождения
- */
- @Test
- void testBirthday() throws Exception {
- User user = new User("user1234@test",
- "user1234",
- "Testing user",
- LocalDate.now().plusDays(30));
-
- String jsonString = gson.toJson(user);
- // Создание пользователя с датой рождения в будущем
- // должно возвращать статус 400 "BadRequest"
- mvc.perform(post("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest());
-
- user.setBirthday(LocalDate.now().minusYears(30));
- jsonString = gson.toJson(user);
- // Создание тестового пользователя с корректной датой рождения
- // должно возвращать статус 200 "Ok"
- mvc.perform(post("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isCreated());
- }
-
- /**
- * Тестируем группу аннотаций для режима обновления данных
- */
- @Test
- void testUpdateUser() throws Exception {
- User user = new User("user1234@test",
- "user1234",
- "Testing user",
- LocalDate.now().minusYears(32));
- String jsonString = gson.toJson(user);
- // Создание тестового пользователя
- // должно возвращать статус 201 "Created"
- mvc.perform(post("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isCreated());
-
- jsonString = "{\"id\": 1, \"email\": \"user.domain@\"}";
- // Изменение пользователю email на некорректный
- // должно возвращать статус 400 "BadRequest"
- mvc.perform(put("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest());
-
- jsonString = "{\"id\": 1, \"email\": \"user@host.domain\"}";
- // Изменение пользователю email на допустимый
- // должно возвращать статус 200 "Ok"
- mvc.perform(put("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk());
-
- jsonString = "{\"id\": 1, \"login\": \"user test12\"}";
- // Изменение пользователю login на некорректный
- // должно возвращать статус 400 "BadRequest"
- mvc.perform(put("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest());
-
- jsonString = "{\"id\": 1, \"login\": \"userTest\"}";
- // Изменение пользователю login на допустимый
- // должно возвращать статус 200 "Ok"
- mvc.perform(put("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk());
-
- jsonString = "{\"id\": 1, \"birthday\": \"2050-01-01\"}";
- // Обновление пользователя с датой рождения в будущем
- // должно возвращать статус 400 "BadRequest"
- mvc.perform(put("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isBadRequest());
-
- jsonString = "{\"id\": 1, \"birthday\": \"2005-01-01\"}";
- // Обновление пользователя корректной датой рождения
- // должно возвращать статус 200 "Ok"
- mvc.perform(put("/users")
- .content(jsonString)
- .contentType(MediaType.APPLICATION_JSON))
- .andExpect(status().isOk());
- }
-}
diff --git a/src/test/java/ru/yandex/practicum/filmorate/model/UserTest.java b/src/test/java/ru/yandex/practicum/filmorate/model/UserTest.java
index 2e61eb5..43a2218 100644
--- a/src/test/java/ru/yandex/practicum/filmorate/model/UserTest.java
+++ b/src/test/java/ru/yandex/practicum/filmorate/model/UserTest.java
@@ -1,3 +1,4 @@
+
package ru.yandex.practicum.filmorate.model;
import jakarta.validation.ConstraintViolation;
@@ -6,6 +7,7 @@
import jakarta.validation.ValidatorFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import ru.yandex.practicum.filmorate.validator.Marker;
import java.time.LocalDate;
import java.util.Set;
@@ -15,10 +17,7 @@
/**
* Тестирование ограничений на значения полей класса User.
- * Автономный тест (Junit).
*/
-// @SpringBootTest
-// @AutoConfigureMockMvc
class UserTest {
private Validator validator;
diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorageTest.java
new file mode 100644
index 0000000..362fc38
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/storage/film/FilmDbStorageTest.java
@@ -0,0 +1,211 @@
+package ru.yandex.practicum.filmorate.storage.film;
+
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.Import;
+import ru.yandex.practicum.filmorate.model.Film;
+import ru.yandex.practicum.filmorate.model.Genre;
+import ru.yandex.practicum.filmorate.model.Mpa;
+
+import java.time.LocalDate;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Тестирование Хранилища Фильмов в базе данных
+ *
+ * Для успешного выполнения тестов, при инициализации базы данных
+ * должна быть подготовлена информация о четырех тестовых фильмах.
+ * Для фильма с id=TEST_FILM_ID нужно создать запись в таблице жанров.
+ * Файл первоначальных данных ./src/test/resources/data.sql
+ */
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@Import({FilmDbStorage.class})
+class FilmDbStorageTest {
+ public static final int TEST_FILM_ID = 1;
+
+ private final FilmDbStorage filmDbStorage;
+
+ /**
+ * Генерация информации о тестовом фильме
+ * Поля должны соответствовать содержимому базы данных для фильма TEST_FILM_ID
+ *
+ * @return - объект, который ожидается для TEST_FILM_ID
+ */
+ static Film getTestFilm() {
+ Film film = new Film();
+ film.setId(TEST_FILM_ID);
+ film.setName("TestFilmName");
+ film.setDescription("TestFilmDescription");
+ film.setReleaseDate(LocalDate.of(2001, 2, 3));
+ film.setDuration(51);
+ film.setMpa(new Mpa(1));
+ film.addGenre(new Genre(1, "Комедия"));
+ return film;
+ }
+
+ /**
+ * Тестирование добавления информации о новом фильме
+ */
+ @Test
+ void addNewFilm() {
+ Film film = new Film();
+ film.setName("Фильм! Фильм! Фильм!");
+ film.setDescription("Юмористический рссказ о том, как делают кино.");
+ film.setReleaseDate(LocalDate.of(1968, 9, 1));
+ film.setDuration(20);
+ film.setMpa(new Mpa(1));
+ film.addGenre(new Genre(1, "Комедия"));
+ film.addGenre(new Genre(3, "Мультфильм"));
+
+ Film filmDb = filmDbStorage.addNewFilm(film);
+ assertNotNull(filmDb.getId(),
+ "При добавлении нового фильа должен быть присвоен ненулевой идентификатор.");
+
+ // Сравниваем исходный фильм с сохраненным по всем полям
+ Optional filmOptional = filmDbStorage.getFilmById(filmDb.getId());
+ assertThat(filmOptional)
+ .isPresent()
+ .get()
+ .usingRecursiveComparison()
+ .isEqualTo(filmDb);
+ }
+
+ /**
+ * Тестирование чтения информации о фильме по заданному идентификатору
+ */
+ @Test
+ void getFilmById() {
+ Film film = getTestFilm();
+ Optional filmOptional;
+
+ // Попытка чтения несушествующего фильма
+ filmOptional = filmDbStorage.getFilmById(10000);
+ assertThat(filmOptional)
+ .withFailMessage("При чтении несуществующего фильма должен возвращаться пустой объект")
+ .isEmpty();
+
+ filmOptional = filmDbStorage.getFilmById(film.getId());
+ assertThat(filmOptional)
+ .isPresent()
+ .get()
+ .isEqualTo(film);
+ }
+
+ /**
+ * Тестирование списка фильмов
+ */
+ @Test
+ void findAllFilms() {
+ Collection films = filmDbStorage.findAllFilms();
+ assertTrue(films.size() > 0,
+ "findAllFilms() - В базе данных отсутствует информация о фильмах.");
+ }
+
+ /**
+ * Тестирование расчета популярности фильмов
+ */
+ @Test
+ void findPopularFilms() {
+ // задаем "лайки" к фильмам
+ filmDbStorage.addNewLike(1, 1);
+ filmDbStorage.addNewLike(2, 1);
+ filmDbStorage.addNewLike(2, 2);
+ filmDbStorage.addNewLike(3, 1);
+ filmDbStorage.addNewLike(3, 2);
+ filmDbStorage.addNewLike(3, 3);
+ filmDbStorage.addNewLike(3, 4);
+ filmDbStorage.addNewLike(4, 4);
+ filmDbStorage.addNewLike(4, 2);
+ filmDbStorage.addNewLike(4, 3);
+
+ Collection films = filmDbStorage.findPopularFilms(2);
+ List popular = new LinkedList<>(films);
+ assertEquals(popular.get(0), filmDbStorage.getFilmById(3).get(),
+ "Самый популярный фильм расчитан неверно.");
+
+ assertEquals(popular.get(1), filmDbStorage.getFilmById(4).get(),
+ "Второй по популярности фильм расчитан неверно.");
+ }
+
+ /**
+ * Тестирование обновления информации о фильме
+ */
+ @Test
+ void updateFilm() {
+ Film film = getTestFilm();
+ film.setName("filmNameUpdated");
+ film.setReleaseDate(LocalDate.of(1999, 12, 31));
+ film.addGenre(new Genre(6, "Боевик"));
+
+ filmDbStorage.updateFilm(film);
+
+ Optional filmOptional = filmDbStorage.getFilmById(film.getId());
+ assertThat(filmOptional)
+ .isPresent()
+ .get()
+ .isEqualTo(film);
+ }
+
+ /**
+ * Тестирование добавления "лайка" к фильму
+ */
+ @Test
+ void addNewLike() {
+ Film film = getTestFilm();
+ film.setId(null);
+ film.setName("TestLikeFilmName");
+ film.setDescription("TestLikeFilmDescription");
+
+ Film filmDb = filmDbStorage.addNewFilm(film);
+
+ Integer rank = filmDbStorage.addNewLike(filmDb.getId(), 1);
+ assertEquals(1, rank, "При добавлении \"лйка\" произошла ошибка.");
+
+ rank = filmDbStorage.addNewLike(filmDb.getId(), 3);
+ assertEquals(2, rank, "При подсчете \"лйков\" произошла ошибка.");
+
+ rank = filmDbStorage.addNewLike(filmDb.getId(), 3);
+ assertEquals(2, rank, "При добавлении повторного \"лйка\" произошла ошибка счетчика.");
+ }
+
+ /**
+ * Тестирование удаления "лайка у фильма"
+ */
+ @Test
+ void removeLike() {
+ final int userId = 1;
+
+ Integer expectedRank = filmDbStorage.addNewLike(TEST_FILM_ID, userId) - 1;
+ Integer rank = filmDbStorage.removeLike(TEST_FILM_ID, userId);
+
+ assertEquals(expectedRank, rank,
+ "При удалении \"лайка\" произошла ошибка.");
+ }
+
+ /**
+ * Тестирование Удаления информации о всех фильмах
+ */
+ @Test
+ void removeAllFilms() {
+ Film film = getTestFilm();
+ film.setId(null);
+ film.setName("TestFilmNameForRmove");
+ filmDbStorage.addNewFilm(film);
+
+ filmDbStorage.removeAllFilms();
+ Collection films = filmDbStorage.findAllFilms();
+ assertTrue(films.size() == 0,
+ "При удалении фильмов произошла ошибка.");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/genre/GenreDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/genre/GenreDbStorageTest.java
new file mode 100644
index 0000000..27c146b
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/storage/genre/GenreDbStorageTest.java
@@ -0,0 +1,77 @@
+package ru.yandex.practicum.filmorate.storage.genre;
+
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.Import;
+import ru.yandex.practicum.filmorate.model.Genre;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Тестирование справочника жанров фильа
+ *
+ * Для успешного выполнения тестов, при инициализации базы данных
+ * должндолжен быть полностью заполнен справочник жанров.
+ * Файл первоначальных данных ./src/test/resources/data.sql
+ */
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@Import({GenreDbStorage.class})
+class GenreDbStorageTest {
+
+ private final GenreDbStorage genreDbStorage;
+ private static final List testGenres = new ArrayList<>();
+
+ /**
+ * Инициализация эталонного списка жанров.
+ */
+ @BeforeAll
+ static void setUp() {
+ testGenres.add(new Genre(1, "Комедия"));
+ testGenres.add(new Genre(2, "Драма"));
+ testGenres.add(new Genre(3, "Мультфильм"));
+ testGenres.add(new Genre(4, "Триллер"));
+ testGenres.add(new Genre(5, "Документальный"));
+ testGenres.add(new Genre(6, "Боевик"));
+ }
+
+ /**
+ * Тестирование списка жанров
+ */
+ @Test
+ void findAllGenres() {
+ Collection genres = genreDbStorage.findAllGenres();
+ for (Genre genre : testGenres) {
+ assertTrue(genres.contains(genre),
+ "В базе данных отсутствует " + genre.toString());
+ }
+ }
+
+ /**
+ * Тестирование поиска жанров по идентификатору
+ */
+ @Test
+ void findGenre() {
+ for (Genre genre : testGenres) {
+ Optional genreOptional = genreDbStorage.findGenre(genre.getId());
+
+ assertThat(genreOptional)
+ .isPresent()
+ .get()
+ .usingRecursiveComparison()
+ .isEqualTo(genre);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/mpa/MpaDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/mpa/MpaDbStorageTest.java
new file mode 100644
index 0000000..8fb0bc7
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/storage/mpa/MpaDbStorageTest.java
@@ -0,0 +1,75 @@
+package ru.yandex.practicum.filmorate.storage.mpa;
+
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.Import;
+import ru.yandex.practicum.filmorate.model.Mpa;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Тестирование справочника рейтингов фильа
+ *
+ * Для успешного выполнения тестов, при инициализации базы данных
+ * должндолжен быть полностью заполнен справочник рейтингов MPA.
+ * Файл первоначальных данных ./src/test/resources/data.sql
+ */
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@Import({MpaDbStorage.class})
+class MpaDbStorageTest {
+
+ private final MpaDbStorage mpaDbStorage;
+ private static List testMpaList = new ArrayList<>();
+
+ /**
+ * Инициализация эталонного списка рейтингов.
+ */
+ @BeforeAll
+ static void setUp() {
+ testMpaList.add(new Mpa(1, "G", "у фильма нет возрастных ограничений"));
+ testMpaList.add(new Mpa(2, "PG", "детям рекомендуется смотреть фильм с родителями"));
+ testMpaList.add(new Mpa(3, "PG-13", "детям до 13 лет просмотр не желателен"));
+ testMpaList.add(new Mpa(4, "R", "лицам до 17 лет просматривать фильм можно только в присутствии взрослого"));
+ testMpaList.add(new Mpa(5, "NC-17", "лицам до 18 лет просмотр запрещён"));
+ }
+
+ /**
+ * Тестирование списка рейтингов
+ */
+ @Test
+ void findAllMpa() {
+ Collection genres = mpaDbStorage.findAllMpa();
+ for (Mpa mpa : testMpaList) {
+ assertTrue(genres.contains(mpa),
+ "В базе данных отсутствует " + mpa.toString());
+ }
+ }
+
+ /**
+ * Тестирование поиска рейтинга по идентификатору
+ */
+ @Test
+ void findMpaById() {
+ for (Mpa mpa : testMpaList) {
+ Optional mpaOptional = mpaDbStorage.findMpa(mpa.getId());
+ assertThat(mpaOptional)
+ .isPresent()
+ .get()
+ .usingRecursiveComparison()
+ .isEqualTo(mpa);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorageTest.java b/src/test/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorageTest.java
new file mode 100644
index 0000000..40632ae
--- /dev/null
+++ b/src/test/java/ru/yandex/practicum/filmorate/storage/user/UserDbStorageTest.java
@@ -0,0 +1,238 @@
+package ru.yandex.practicum.filmorate.storage.user;
+
+import lombok.RequiredArgsConstructor;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
+import org.springframework.context.annotation.Import;
+import org.springframework.dao.DuplicateKeyException;
+import ru.yandex.practicum.filmorate.model.User;
+
+import java.time.LocalDate;
+import java.util.Collection;
+import java.util.Optional;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Тестирование Хранилища пользователей в базе данных
+ *
+ * Для успешного выполнения тестов, при инициализации базы данных
+ * должна быть подготовлена информация о четырех тестовых пользователях.
+ * Файл первоначальных данных ./src/test/resources/data.sql
+ */
+@JdbcTest
+@AutoConfigureTestDatabase
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
+@Import({UserDbStorage.class})
+class UserDbStorageTest {
+ public static final int TEST_USER_ID = 1;
+
+ private final UserDbStorage userDbStorage;
+
+ /**
+ * Генерация тестового пользователя
+ *
+ * @return - Optional информация о пользователе если найден
+ */
+ static User getTestUser() {
+ User user = new User();
+ user.setId(TEST_USER_ID);
+ user.setEmail("test@test.com");
+ user.setLogin("testLogin");
+ user.setName("testName");
+ user.setBirthday(LocalDate.of(2001, 9, 22));
+ return user;
+ }
+
+ /**
+ * Чтение информации о тестовом пользователе по заданному идентификатору.
+ */
+ @Test
+ void getUserById() {
+ User user = getTestUser();
+ Optional userOptional = userDbStorage.getUserById(1);
+
+ assertThat(userOptional)
+ .isPresent()
+ .get()
+ .usingRecursiveComparison()
+ .isEqualTo(user);
+ }
+
+ /**
+ * Тест добавления в базу данных нового пользователя
+ */
+ @Test
+ void addNewUser() {
+ User user = new User();
+ user.setName("TesstUserName");
+ user.setLogin("TestUserLogin");
+ user.setBirthday(LocalDate.of(2001, 7, 22));
+
+ // Проверяем попытку добавить пользвателя с неуникальным Email
+ user.setEmail(getTestUser().getEmail());
+ assertThrows(DuplicateKeyException.class,
+ () -> {
+ userDbStorage.addNewUser(user);
+ },
+ "Попытка записи неуникального значения Email должна приводить к исключению.");
+
+ // меняем Email на уникальный
+ user.setEmail("test@user.test");
+ User userDb = userDbStorage.addNewUser(user);
+ assertNotNull(userDb.getId(),
+ "addNewUser() - При добавлении пользователя в базу должен быть присвоен не нулевой идентификатор");
+
+ Optional userOptional = userDbStorage.getUserById(userDb.getId());
+ assertThat(userOptional)
+ .isPresent()
+ .get()
+ .usingRecursiveComparison()
+ .isEqualTo(user);
+ }
+
+ /**
+ * Тестирование поиска информации о всех пользователях в базе.
+ */
+ @Test
+ void findAllUsers() {
+ Collection users = userDbStorage.findAllUsers();
+
+ assertTrue(users.size() > 0,
+ "findAllUsers() - В базе данных отсутствует информация о пользователях.");
+ }
+
+ /**
+ * Тестирование обновления информации о тестовом пользователе.
+ */
+ @Test
+ void updateUser() {
+ User userUpdate = getTestUser();
+ userUpdate.setEmail("updated_user@test.com");
+
+ userDbStorage.updateUser(userUpdate);
+
+ Optional userOptional = userDbStorage.getUserById(userUpdate.getId());
+
+ assertThat(userOptional)
+ .isPresent()
+ .get()
+ .usingRecursiveComparison()
+ .isEqualTo(userUpdate);
+ }
+
+ /**
+ * Тестирование добавления "друга"
+ */
+ @Test
+ void addFriend() {
+ final int userId = TEST_USER_ID;
+ final int friendId = 2;
+
+ Optional userOptional = userDbStorage.getUserById(userId);
+ assertThat(userOptional)
+ .withFailMessage("addFriend() - Не определен пользователь id=%s для создания \"друзей\".", userId)
+ .isPresent();
+ if (userOptional.isEmpty()) return;
+
+ userOptional = userDbStorage.getUserById(friendId);
+ assertThat(userOptional)
+ .withFailMessage("addFriend() - Не определен пользователь id=%s в качестве нового \"друга\".", friendId)
+ .isPresent();
+ if (userOptional.isEmpty()) return;
+ User friend = userOptional.get();
+
+ userDbStorage.addFriend(userId, friendId);
+ Collection friends = userDbStorage.getUserFriends(userId);
+
+ assertTrue(friends.contains(friend),
+ "addFriend() - Пользователь id=" + userId + ". не удалось добавить друга id=" + friendId);
+ }
+
+ /**
+ * Тестирование списка друзей заданного пользователя
+ */
+ @Test
+ void getUserFriends() {
+ userDbStorage.addFriend(TEST_USER_ID, 2);
+ userDbStorage.addFriend(TEST_USER_ID, 3);
+ userDbStorage.addFriend(TEST_USER_ID, 4);
+
+ Collection friends = userDbStorage.getUserFriends(TEST_USER_ID);
+ assertTrue(friends.size() > 0,
+ "getUserFriends() - Список друзй пользователя id="
+ + TEST_USER_ID + " не найден.");
+ assertTrue(friends.size() == 3,
+ "getUserFriends() - Количество друзй пользователя id="
+ + TEST_USER_ID + " не соответствует ожидаемому.");
+
+ User testFriend = userDbStorage.getUserById(2).get();
+ assertTrue(friends.contains(testFriend),
+ "getUserFriends() - В списке друзей не найден " + testFriend.toString());
+
+ testFriend = userDbStorage.getUserById(3).get();
+ assertTrue(friends.contains(testFriend),
+ "getUserFriends() - В списке друзей не найден " + testFriend.toString());
+
+ testFriend = userDbStorage.getUserById(4).get();
+ assertTrue(friends.contains(testFriend),
+ "getUserFriends() - В списке друзей не найден " + testFriend.toString());
+ }
+
+ /**
+ * Тестирование удаления пользователя из друзей
+ */
+ @Test
+ void removeFriend() {
+ final int deletedFriendId = 3;
+ getUserFriends();
+
+ userDbStorage.breakUpFriends(TEST_USER_ID, deletedFriendId);
+ Collection friends = userDbStorage.getUserFriends(TEST_USER_ID);
+
+ Optional friend = friends.stream()
+ .filter(user -> user.getId() == deletedFriendId)
+ .findFirst();
+
+ assertThat(friend)
+ .withFailMessage("removeFriend() - пользователь id=%s не был удален из \"друзей\"%s.",
+ deletedFriendId, TEST_USER_ID)
+ .isEmpty();
+ }
+
+ /**
+ * Тестирование поиска общих друзей
+ */
+ @Test
+ void findCommonFriends() {
+ getUserFriends();
+ userDbStorage.addFriend(3, 1);
+ userDbStorage.addFriend(3, 4);
+
+ Collection friends = userDbStorage.getCommonFriends(TEST_USER_ID, 3);
+ Optional commonFriend = friends.stream().findFirst();
+
+ assertThat(commonFriend)
+ .isPresent()
+ .hasValueSatisfying(user ->
+ assertThat(user)
+ .hasFieldOrPropertyWithValue("id", 4));
+ }
+
+ /**
+ * Тестирование удаления пользователей
+ */
+ @Test
+ void removeAllUsers() {
+ addNewUser();
+
+ userDbStorage.removeAllUsers();
+ Collection users = userDbStorage.findAllUsers();
+
+ assertTrue(users.size() == 0,
+ "removeAllUsers() - Не удалось удалить всех пользователей.");
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
new file mode 100644
index 0000000..71a0274
--- /dev/null
+++ b/src/test/resources/application.properties
@@ -0,0 +1,8 @@
+spring.sql.init.mode=always
+spring.datasource.url=jdbc:h2:file:./db/filmorate
+spring.datasource.driverClassName=org.h2.Driver
+spring.datasource.username=sa
+spring.datasource.password=password
+
+server.port=8080
+logging.level.org.zalando.logbook: TRACE
diff --git a/src/test/resources/data.sql b/src/test/resources/data.sql
new file mode 100644
index 0000000..b070a66
--- /dev/null
+++ b/src/test/resources/data.sql
@@ -0,0 +1,34 @@
+-- Заполняем справочник жанров
+MERGE INTO genres (id, name)
+ VALUES ( 1, 'Комедия'),
+ (2, 'Драма'),
+ (3, 'Мультфильм'),
+ (4, 'Триллер'),
+ (5, 'Документальный'),
+ (6, 'Боевик');
+
+-- Заполняем справочник рейтингов MPA
+MERGE INTO MPA (id, name, description)
+ VALUES (1, 'G', 'у фильма нет возрастных ограничений'),
+ (2, 'PG', 'детям рекомендуется смотреть фильм с родителями'),
+ (3, 'PG-13', 'детям до 13 лет просмотр не желателен'),
+ (4, 'R', 'лицам до 17 лет просматривать фильм можно только в присутствии взрослого'),
+ (5, 'NC-17', 'лицам до 18 лет просмотр запрещён');
+
+-- Создаем тестовоых пользователей
+INSERT INTO users (email, login, name, birthday)
+VALUES ( 'test@test.com', 'testLogin', 'testName', '2001-9-22' ),
+ ('user1@test.com', 'userTest1', 'userNane1', '2001-01-01'),
+ ('user2@test.com', 'userTest2', 'userNane2', '2002-02-02'),
+ ('user3@test.com', 'userTest3', 'userNane3', '2003-03-03');
+
+-- Создаем тестовые фильмы
+INSERT INTO films (name, description, releasedate, len_min, mpa_id)
+VALUES ( 'TestFilmName', 'TestFilmDescription', '2001-02-03', 51, 1),
+ ( 'TestFilmName2', 'TestFilmDescription2', '2002-03-04', 62, 2),
+ ( 'TestFilmName3', 'TestFilmDescription3', '2003-04-05', 73, 3),
+ ( 'TestFilmName4', 'TestFilmDescription4', '2004-05-06', 92, 4);
+
+INSERT INTO films_genres (film_id, genre_id)
+VALUES ( 1, 1 );
+
diff --git a/src/test/resources/schema.sql b/src/test/resources/schema.sql
new file mode 100644
index 0000000..714f97c
--- /dev/null
+++ b/src/test/resources/schema.sql
@@ -0,0 +1,53 @@
+-- Создаем таблицу пользователей
+CREATE TABLE IF NOT EXISTS users (
+ id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
+ email VARCHAR(255) UNIQUE NOT NULL,
+ login VARCHAR(40) NOT NULL,
+ name VARCHAR(40) NOT NULL,
+ birthday DATE NOT NULL
+ );
+
+-- Создаем таблицу друзей
+CREATE TABLE IF NOT EXISTS friends (
+ user_id INTEGER NOT NULL REFERENCES users(id),
+ friend_id INTEGER NOT NULL REFERENCES users(id),
+ confirmed BOOLEAN NOT NULL DEFAULT FALSE,
+ PRIMARY KEY (user_id, friend_id)
+ );
+
+-- Создаем справочник жанров фильма
+CREATE TABLE IF NOT EXISTS genres (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(40) NOT NULL
+ );
+
+-- Создаем справочник рейтинга MPA
+CREATE TABLE IF NOT EXISTS MPA (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(8) NOT NULL,
+ description VARCHAR(80)
+ );
+
+-- Создаем таблицу описания фильма
+CREATE TABLE IF NOT EXISTS films (
+ id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
+ name VARCHAR(40) NOT NULL,
+ description VARCHAR(200),
+ releaseDate DATE,
+ len_min INTEGER,
+ MPA_id INTEGER NOT NULL REFERENCES MPA(id)
+ );
+
+-- Создаем таблицу описания жанра фильма
+CREATE TABLE IF NOT EXISTS films_genres (
+ film_id INTEGER NOT NULL REFERENCES films(id),
+ genre_id INTEGER NOT NULL REFERENCES genres(id),
+ PRIMARY KEY (film_id, genre_id)
+ );
+
+-- Создаем таблицу "лайков" к фильмам
+CREATE TABLE IF NOT EXISTS likes (
+ user_id INTEGER NOT NULL REFERENCES users(id),
+ film_id INTEGER NOT NULL REFERENCES films(id),
+ PRIMARY KEY (user_id, film_id)
+ );