From e80d70f3966ff0651697a5dd3e48d991c8fda075 Mon Sep 17 00:00:00 2001 From: TKNguyen12a9 Date: Sat, 21 Jan 2023 18:54:19 +0900 Subject: [PATCH 01/10] add h2database and spring security test dependencies for testing --- movie-api/pom.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/movie-api/pom.xml b/movie-api/pom.xml index 61d57cf..ed01682 100644 --- a/movie-api/pom.xml +++ b/movie-api/pom.xml @@ -40,6 +40,12 @@ org.springframework.boot spring-boot-starter-validation + + + org.springframework.security + spring-security-test + test + @@ -89,6 +95,13 @@ spring-boot-starter-test test + + + + com.h2database + h2 + runtime + From ad95b0694169a567e1d99d29c281ed91ee641fd0 Mon Sep 17 00:00:00 2001 From: TKNguyen12a9 Date: Sat, 21 Jan 2023 18:55:33 +0900 Subject: [PATCH 02/10] add test properties for testing with h2database --- .../resources/application-test.properties | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 movie-api/src/main/resources/application-test.properties diff --git a/movie-api/src/main/resources/application-test.properties b/movie-api/src/main/resources/application-test.properties new file mode 100644 index 0000000..c1c3e9e --- /dev/null +++ b/movie-api/src/main/resources/application-test.properties @@ -0,0 +1,20 @@ +## H2 Test Database creds +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=password +spring.datasource.initialization-mode=always +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +spring.h2.console.enabled=true +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.show-sql =true + + +# SQL scripts +sql.script.insert.user=INSERT INTO users (id, email, image_url, name, password, provider, provider_id, role, username) \ + VALUES (11, 'kane@test.com', NULL, 'kane', '@kien12a99', 'LOCAL', 1, 'USER', 'Kane'); +sql.script.delete.users=DELETE FROM users + +sql.script.insert.movie=INSERT INTO movies (imdb, title, poster) \ + values ('tt01171998', 'No home away', 'cudayanh1'); +sql.script.delete.movies=DELETE FROM movies; \ No newline at end of file From 39fd5b1f7200ab683fdae79ac545d5954c4a6fbe Mon Sep 17 00:00:00 2001 From: TKNguyen12a9 Date: Sat, 21 Jan 2023 18:57:59 +0900 Subject: [PATCH 03/10] add some beans and its scopes for testing --- .../movieapi/MovieApiApplication.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/movie-api/src/main/java/com/ivanfranchin/movieapi/MovieApiApplication.java b/movie-api/src/main/java/com/ivanfranchin/movieapi/MovieApiApplication.java index 9d9e341..b2a25c2 100644 --- a/movie-api/src/main/java/com/ivanfranchin/movieapi/MovieApiApplication.java +++ b/movie-api/src/main/java/com/ivanfranchin/movieapi/MovieApiApplication.java @@ -2,6 +2,13 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Scope; + +import com.ivanfranchin.movieapi.model.Movie; +import com.ivanfranchin.movieapi.model.User; +import com.ivanfranchin.movieapi.rest.dto.LoginRequest; +import com.ivanfranchin.movieapi.rest.dto.SignUpRequest; @SpringBootApplication public class MovieApiApplication { @@ -9,4 +16,28 @@ public class MovieApiApplication { public static void main(String[] args) { SpringApplication.run(MovieApiApplication.class, args); } + + @Bean + @Scope(value = "prototype") + User getUser() { + return new User(); + } + + @Bean + @Scope(value = "prototype") + Movie getMovie() { + return new Movie(); + } + + @Bean + @Scope(value = "prototype") + LoginRequest getLoginRequest() { + return new LoginRequest(); + } + + @Bean + @Scope(value = "prototype") + SignUpRequest getSignUpRequest() { + return new SignUpRequest(); + } } From 45e6ad76a9f3508563139e66e292870b9978c2a0 Mon Sep 17 00:00:00 2001 From: TKNguyen12a9 Date: Sat, 21 Jan 2023 19:00:35 +0900 Subject: [PATCH 04/10] add findByImdb for more testing options --- .../com/ivanfranchin/movieapi/repository/MovieRepository.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/movie-api/src/main/java/com/ivanfranchin/movieapi/repository/MovieRepository.java b/movie-api/src/main/java/com/ivanfranchin/movieapi/repository/MovieRepository.java index bea6ff8..4b63fe6 100644 --- a/movie-api/src/main/java/com/ivanfranchin/movieapi/repository/MovieRepository.java +++ b/movie-api/src/main/java/com/ivanfranchin/movieapi/repository/MovieRepository.java @@ -5,6 +5,7 @@ import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Optional; @Repository public interface MovieRepository extends JpaRepository { @@ -12,4 +13,6 @@ public interface MovieRepository extends JpaRepository { List findAllByOrderByTitle(); List findByImdbContainingOrTitleContainingOrderByTitle(String imdb, String title); + + Optional findByImdb(String imdb); } From b7eb74571423654fe5eba3682f24b3e7568ec6c9 Mon Sep 17 00:00:00 2001 From: TKNguyen12a9 Date: Sat, 21 Jan 2023 19:10:42 +0900 Subject: [PATCH 05/10] update hard-coded ADMIN, USER roles as hasAnyAuthority() requires prefix ROLE --- .../com/ivanfranchin/movieapi/security/WebSecurityConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/movie-api/src/main/java/com/ivanfranchin/movieapi/security/WebSecurityConfig.java b/movie-api/src/main/java/com/ivanfranchin/movieapi/security/WebSecurityConfig.java index f43cedc..ba50090 100644 --- a/movie-api/src/main/java/com/ivanfranchin/movieapi/security/WebSecurityConfig.java +++ b/movie-api/src/main/java/com/ivanfranchin/movieapi/security/WebSecurityConfig.java @@ -59,6 +59,6 @@ public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } - public static final String ADMIN = "ADMIN"; - public static final String USER = "USER"; + public static final String ADMIN = "ROLE_ADMIN"; + public static final String USER = "ROLE_USER"; } From cdd0ff29039e6aa80c34e1a20696169880a69098 Mon Sep 17 00:00:00 2001 From: TKNguyen12a9 Date: Sat, 21 Jan 2023 19:11:35 +0900 Subject: [PATCH 06/10] add test for movieController --- .../movieapi/movie/MovieControllerTest.java | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 movie-api/src/test/java/com/ivanfranchin/movieapi/movie/MovieControllerTest.java diff --git a/movie-api/src/test/java/com/ivanfranchin/movieapi/movie/MovieControllerTest.java b/movie-api/src/test/java/com/ivanfranchin/movieapi/movie/MovieControllerTest.java new file mode 100644 index 0000000..66a42b3 --- /dev/null +++ b/movie-api/src/test/java/com/ivanfranchin/movieapi/movie/MovieControllerTest.java @@ -0,0 +1,184 @@ +package com.ivanfranchin.movieapi.movie; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.transaction.annotation.Transactional; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.hamcrest.CoreMatchers.*; // is() +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ivanfranchin.movieapi.model.Movie; +import com.ivanfranchin.movieapi.repository.MovieRepository; +import com.ivanfranchin.movieapi.service.MovieService; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + +@TestPropertySource("/application-test.properties") +@AutoConfigureMockMvc(addFilters = false) +@SpringBootTest +@Transactional +public class MovieControllerTest { + + @PersistenceContext + private EntityManager entityManager; + + private static MockHttpServletRequest mockHttpRequest; + + @Mock + private MovieService movieService; + + @Autowired + private MovieRepository movieRepository; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private Movie movie; + + @Autowired + private JdbcTemplate jdbc; + + @Value("${sql.script.insert.movie}") + private String sqlInsertMovie; + + @Value("${sql.script.delete.movies}") + private String sqlDeleteMovie; + + @Value("${sql.script.insert.user}") + private String sqlInsertUser; + + @Value("${sql.script.delete.users}") + private String sqlDeleteUser; + + public static final MediaType APPLICATION_JSON_UTF8 = MediaType.APPLICATION_JSON; + + @BeforeAll + static void setupMock() { + mockHttpRequest = new MockHttpServletRequest(); + + mockHttpRequest.setParameter("imdb", "tt0163111"); + mockHttpRequest.setParameter("title", "today, now"); + mockHttpRequest.setParameter("poster", "admin"); + } + + @BeforeEach + void setupDbBeforeTransactions() throws Exception { + jdbc.execute(sqlInsertMovie); + jdbc.execute(sqlInsertUser); + } + + @Test + void getNumberOfMoviesHttpRequest() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/public/numberOfMovies")) + .andExpect(status().isOk()).andExpect(jsonPath("$", is(11))); + } + + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void getMovieByTextHttpRequest() throws Exception { + String text = "home"; + mockMvc.perform(MockMvcRequestBuilders.get("/api/movies").param("text", text)) + .andExpect(status().isOk()) + .andDo(print()) + .andExpect(jsonPath("$").isArray()); + } + + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void createInvalidMovieHttpRequest() throws Exception { + String blankImdb = ""; + mockMvc.perform(MockMvcRequestBuilders.post("/api/movies") + .contentType(MediaType.APPLICATION_JSON) + .param("imdb", blankImdb) + .param("title", "test title") + .param("poster", "Me")) + .andExpect(status().isBadRequest()) + .andDo(print()); + } + + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void createMovieHttpRequest() throws Exception { + String imdb = "tt0163111"; + String title = "today, now"; + String poster = "admin"; + + movie.setImdb(imdb); + movie.setTitle(title); + movie.setPoster(poster); + + assertFalse(movieRepository.findByImdb(imdb).isPresent(), "should return false"); + + mockMvc.perform(MockMvcRequestBuilders.post("/api/movies") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(movie))) + .andExpect(status().isCreated()) + .andExpect(content().contentType(APPLICATION_JSON_UTF8)) + .andExpect(jsonPath("$.imdb", is(imdb))) + .andExpect(jsonPath("$.title", is(title))) + .andExpect(jsonPath("$.poster", is(poster))) + .andExpect(jsonPath("$.createdAt", is(notNullValue()))) + .andDo(print()); + + assertTrue(movieRepository.findByImdb(imdb).isPresent(), "should return true"); + } + + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void deleteNonExistingMovieByImdbHttpRequest() throws Exception { + String imdb = "nonPresentImdb"; + + assertFalse(movieRepository.findByImdb(imdb).isPresent()); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/movies/{imdb}", imdb)) + .andExpect(status().is4xxClientError()) + .andDo(print()); + } + + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void deleteMovieByImdbHttpRequest() throws Exception { + String imdb = "tt01171998"; + + assertTrue(movieRepository.findByImdb(imdb).isPresent(), "should return true"); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/movies/{imdb}", imdb)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.imdb", is(imdb))) + .andExpect(jsonPath("$.title", is("No home away"))) + .andExpect(jsonPath("$.poster", is("cudayanh1"))) + // .andExpect(jsonPath("$.createdAt", is(notNullValue()))) // ? not sure why createdAt sometimes returns null + .andDo(print()); + + assertFalse(movieRepository.findByImdb(imdb).isPresent(), "should return false"); + } + + @AfterEach + void setupDbAfterTransactions() throws Exception { + jdbc.execute(sqlDeleteMovie); + jdbc.execute(sqlDeleteUser); + } +} From 147bd00c9e33308fcf19696be9d4862fb1077453 Mon Sep 17 00:00:00 2001 From: TKNguyen12a9 Date: Sat, 21 Jan 2023 19:11:51 +0900 Subject: [PATCH 07/10] add test for movieService --- .../movieapi/movie/MovieServiceTest.java | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 movie-api/src/test/java/com/ivanfranchin/movieapi/movie/MovieServiceTest.java diff --git a/movie-api/src/test/java/com/ivanfranchin/movieapi/movie/MovieServiceTest.java b/movie-api/src/test/java/com/ivanfranchin/movieapi/movie/MovieServiceTest.java new file mode 100644 index 0000000..35f0dd3 --- /dev/null +++ b/movie-api/src/test/java/com/ivanfranchin/movieapi/movie/MovieServiceTest.java @@ -0,0 +1,100 @@ +package com.ivanfranchin.movieapi.movie; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.TestPropertySource; + +import com.ivanfranchin.movieapi.model.Movie; +import com.ivanfranchin.movieapi.repository.MovieRepository; +import com.ivanfranchin.movieapi.service.MovieService; + +@TestPropertySource("/application-test.properties") +@SpringBootTest +public class MovieServiceTest { + + @Autowired + private JdbcTemplate jdbc; + + @Autowired + private MovieService movieService; + + @Autowired + private MovieRepository movieRepository; + + @Value("${sql.script.insert.movie}") + private String sqlInsertMovie; + + @Value("${sql.script.delete.movies}") + private String sqlDeleteMovie; + + @BeforeEach + void setupDbBeforeTransactions() throws Exception { + jdbc.execute(sqlInsertMovie); + } + + @Test + void isMovieNullCheck() throws Exception { + Movie movie = movieService.validateAndGetMovie("tt01171998"); + assertEquals("tt01171998", movie.getImdb() ,"should return true for movie has `imdb: tt01171998`"); + } + + @Test + void createMovieService() throws Exception { + Movie movie = new Movie("tt01171999", "be strong", "Jane"); + + movieService.saveMovie(movie); + + Movie movieToCheck = movieService.validateAndGetMovie("tt01171999"); + + assertEquals("tt01171999", movieToCheck.getImdb()); + } + + @Test + void getMoviesService() throws Exception { + List movies = movieService.getMovies(); + // there are 10 movies already persisted in db + // NOTE: TRUE if run for just this single case, otherwise FALSE + // assertEquals(11, movies.size(), "should return movies.size() == 11"); + + // NOTE: TRUE if run concurrently with other test cases, otherwise FALSE + assertEquals(1, movies.size(), "should return movies.size() == 11"); + } + + @Test + void getMoviesServiceContainGivenText() throws Exception { + List movies = movieService.getMoviesContainingText("home"); + assertTrue(movies.size() > 0, "should return true for movies.size() > 0"); + assertFalse(movies.size() > 1, "should return for movies.size() > 1"); + assertTrue(movies.size() == 1, "should return for movies.size() == 1"); + } + + @Test + void deleteMovieService() throws Exception { + Optional movie = movieRepository.findByImdb("tt01171998"); + + assertTrue(Optional.of(movie).isPresent(), "should return true"); + + movieService.deleteMovie(movie.get()); + + movie = movieRepository.findByImdb("tt01171998"); + + assertFalse(movie.isPresent(), "should return false"); + } + + @AfterEach + void setupDbAfterTransactions() throws Exception { + jdbc.execute(sqlDeleteMovie); + } +} From 7677ce06c7940b5a1cc3133c23ff9753939a975a Mon Sep 17 00:00:00 2001 From: TKNguyen12a9 Date: Sat, 21 Jan 2023 19:12:03 +0900 Subject: [PATCH 08/10] add test for userController --- .../movieapi/user/UserControllerTest.java | 216 ++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 movie-api/src/test/java/com/ivanfranchin/movieapi/user/UserControllerTest.java diff --git a/movie-api/src/test/java/com/ivanfranchin/movieapi/user/UserControllerTest.java b/movie-api/src/test/java/com/ivanfranchin/movieapi/user/UserControllerTest.java new file mode 100644 index 0000000..9f309f9 --- /dev/null +++ b/movie-api/src/test/java/com/ivanfranchin/movieapi/user/UserControllerTest.java @@ -0,0 +1,216 @@ +package com.ivanfranchin.movieapi.user; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.transaction.annotation.Transactional; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.hamcrest.CoreMatchers.*; // is() +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ivanfranchin.movieapi.model.User; +import com.ivanfranchin.movieapi.repository.UserRepository; +import com.ivanfranchin.movieapi.rest.dto.LoginRequest; +import com.ivanfranchin.movieapi.rest.dto.SignUpRequest; +import com.ivanfranchin.movieapi.service.UserService; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; + + +@TestPropertySource("/application-test.properties") +@AutoConfigureMockMvc(addFilters = false) +@SpringBootTest +@Transactional +public class UserControllerTest { + + @PersistenceContext + private EntityManager entityManager; + + private static MockHttpServletRequest mockHttpRequest; + + @Mock + UserService userService; + + @Autowired + private UserRepository userRepository; + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private LoginRequest loginRequest; + + @Autowired + private SignUpRequest signUpRequest; + + @Autowired + private JdbcTemplate jdbc; + + @Autowired + private User user; + + @MockBean + private JwtDecoder jwtDecoder; + + @Value("${sql.script.insert.user}") + private String sqlInsertUser; + + @Value("${sql.script.delete.users}") + private String sqlDeleteUser; + + public static final MediaType APPLICATION_JSON_UTF8 = MediaType.APPLICATION_JSON; + + @BeforeAll + static void setupMock() { + mockHttpRequest = new MockHttpServletRequest(); + + mockHttpRequest.setParameter("username", "Jane"); + mockHttpRequest.setParameter("email", "jane@test.com"); + } + + @BeforeEach + void setupDbBeforeTransactions() throws Exception { + jdbc.execute(sqlInsertUser); + } + + @Test + void getNumberOfUsersHttpRequest() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/public/numberOfUsers")) + .andExpect(status().isOk()).andExpect(jsonPath("$", is(3))); + } + + @Test + void testAuthenticateUserHttpRequest() throws Exception { + signUpRequest.setEmail("jane@test.com"); + signUpRequest.setUsername("jane"); + signUpRequest.setName("Jane"); + signUpRequest.setPassword("jane"); + + assertFalse(userRepository.findByUsername("jane").isPresent(), "should return false"); + + mockMvc.perform(MockMvcRequestBuilders.post("/auth/signup") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(signUpRequest))) + .andExpect(status().is2xxSuccessful()) + .andExpect(jsonPath("$.accessToken", is(notNullValue()))) + .andDo(print()); + + assertTrue(userRepository.findByUsername("jane").isPresent(), "should return true"); + } + + @Test + void testSignupAuthenticatedUserHttpRequest() throws Exception { + String username = "admin"; + String password = "admin"; + + loginRequest.setUsername(username); + loginRequest.setPassword(password); + + assertTrue(userRepository.findByUsername(username).isPresent(), "should return true"); + + mockMvc.perform(MockMvcRequestBuilders.post("/auth/authenticate") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginRequest)) + ) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.accessToken", is(notNullValue()))) + .andDo(print()); + } + + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void getNonExistingUserByUsernameHttpRequest() throws Exception { + String nonExistingUsername = "Kaneee"; + + assertFalse(userRepository.findByUsername(nonExistingUsername).isPresent(), "should return true"); + + mockMvc.perform(MockMvcRequestBuilders.get("/api/users/{username}", nonExistingUsername)) + .andExpect(status().is4xxClientError()) + .andDo(print()); + } + + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void getUserByUsernameHttpRequest() throws Exception { + user.setEmail("jane@test.com"); + user.setUsername("jane"); + user.setName("Jane"); + user.setPassword("password"); + user.setRole("USER"); + + entityManager.persist(user); + entityManager.flush(); + + assertTrue(userRepository.findByUsername("jane").isPresent(), "should return true"); + + mockMvc.perform(MockMvcRequestBuilders.get("/api/users/{username}", "jane")) + .andExpect(status().isOk()) + .andExpect(content().contentType(APPLICATION_JSON_UTF8)) + .andExpect(jsonPath("$.id", is(3))) + .andExpect(jsonPath("$.username", is("jane"))) + .andExpect(jsonPath("$.name", is( "Jane"))) + .andExpect(jsonPath("$.email", is("jane@test.com"))) + .andExpect(jsonPath("$.role", is("USER"))) + .andDo(print()); + } + + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void deleteNonExistingUserByUsernameHttpRequest() throws Exception { + String nonExistingUsername = "Kaneeee"; + + assertTrue(userRepository.findByUsername("Kane").isPresent(), "should return true for existing username"); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/users/{username}", nonExistingUsername)) + .andExpect(status().is4xxClientError()) + .andDo(print()); + } + + @Test + @WithMockUser(username = "admin", password = "admin", roles = "ADMIN") + void deleteUserByUsernameHttpRequest() throws Exception { + String username = "Kane"; + + assertTrue(userRepository.findByUsername(username).isPresent(), "should return true"); + + mockMvc.perform(MockMvcRequestBuilders.delete("/api/users/{username}", username)) + .andExpect(status().isOk()) + .andExpect(content().contentType(APPLICATION_JSON_UTF8)) + .andExpect(jsonPath("$.id", is(11))) + .andExpect(jsonPath("$.username", is("Kane"))) + .andExpect(jsonPath("$.name", is( "kane"))) + .andExpect(jsonPath("$.email", is("kane@test.com"))) + .andExpect(jsonPath("$.role", is("USER"))) + .andDo(print()); + + assertFalse(userRepository.findByUsername(username).isPresent(), "should return false"); + } + + @AfterEach + void setupDbAfterTransactions() throws Exception { + jdbc.execute(sqlDeleteUser); + } +} From 7706a1f1dd34e4d010c795dea658b4ce50bf1a00 Mon Sep 17 00:00:00 2001 From: TKNguyen12a9 Date: Sat, 21 Jan 2023 19:12:17 +0900 Subject: [PATCH 09/10] add test for userService --- .../movieapi/user/UserServiceTest.java | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 movie-api/src/test/java/com/ivanfranchin/movieapi/user/UserServiceTest.java diff --git a/movie-api/src/test/java/com/ivanfranchin/movieapi/user/UserServiceTest.java b/movie-api/src/test/java/com/ivanfranchin/movieapi/user/UserServiceTest.java new file mode 100644 index 0000000..c3b6717 --- /dev/null +++ b/movie-api/src/test/java/com/ivanfranchin/movieapi/user/UserServiceTest.java @@ -0,0 +1,97 @@ +package com.ivanfranchin.movieapi.user; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.TestPropertySource; +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +import com.ivanfranchin.movieapi.model.User; +import com.ivanfranchin.movieapi.repository.UserRepository; +import com.ivanfranchin.movieapi.security.oauth2.OAuth2Provider; +import com.ivanfranchin.movieapi.service.UserService; + + +@TestPropertySource("/application-test.properties") +@SpringBootTest +public class UserServiceTest { + + @Autowired + private JdbcTemplate jdbc; + + @Autowired + private UserRepository userRepository; + + @Autowired + private UserService userService; + + @Value("${sql.script.insert.user}") + private String sqlInsertUser; + + @Value("${sql.script.delete.users}") + private String sqlDeleteUser; + + @BeforeEach + public void setupDbBeforeTransactions() { + jdbc.execute(sqlInsertUser); + } + + @Test + void getUserServiceByUsername() throws Exception { + assertTrue(userService.hasUserWithUsername("Kane"), "a user named 'Kane' should be created by @setupDbBeforeTransaction"); + } + + @Test + void getUserServiceByInvalidUsername() throws Exception { + assertFalse(userService.hasUserWithUsername("nonExistedUsername"), "should return false for a user with email 'nonExists@test.com'"); + } + + @Test + void getUserServiceByEmail() throws Exception { + Optional user = userService.getUserByEmail("kane@test.com"); + assertTrue(user.isPresent(), "should return true for user with `email: cudayanh1@test.com`"); + } + + @Test + void getUserServiceByInvalidEmail() throws Exception { + Optional user = userService.getUserByEmail("kane1111@test.com"); + assertFalse(user.isPresent(), "should return false for user with `email: cudayanh1111@test.com`"); + } + + @Test + void createUserService() throws Exception { + User user = new User("Jane", "@kien12a9", "jane", + "jane@test.com", "USER", "", OAuth2Provider.LOCAL, "2"); + + userService.saveUser(user); + + Optional userToCheck = userRepository.findByUsername("Jane"); + + assertTrue(userToCheck.isPresent(), "should return true for a user with `username: Jane`"); + } + + @Test + void deleteUserService() throws Exception { + Optional user = userRepository.findByUsername("Kane"); + + assertTrue(user.isPresent(), "should return true for a user named `Kane`"); + + userService.deleteUser(user.get()); + + user = userRepository.findByUsername("Kane"); + + assertFalse(user.isPresent(), "should return false for deleted user named `Kane`"); + } + + @AfterEach + public void setupDbAfterTransactions() { + jdbc.execute(sqlDeleteUser); + } +} From c3ed349821f5dbbe4040d5316420208c61627994 Mon Sep 17 00:00:00 2001 From: TKNguyen12a9 Date: Sat, 21 Jan 2023 19:12:54 +0900 Subject: [PATCH 10/10] remove useless test context --- .../movieapi/MovieApiApplicationTests.java | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 movie-api/src/test/java/com/ivanfranchin/movieapi/MovieApiApplicationTests.java diff --git a/movie-api/src/test/java/com/ivanfranchin/movieapi/MovieApiApplicationTests.java b/movie-api/src/test/java/com/ivanfranchin/movieapi/MovieApiApplicationTests.java deleted file mode 100644 index 2e6ca23..0000000 --- a/movie-api/src/test/java/com/ivanfranchin/movieapi/MovieApiApplicationTests.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.ivanfranchin.movieapi; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@Disabled -@SpringBootTest -class MovieApiApplicationTests { - - @Test - void contextLoads() { - } -}