-
Notifications
You must be signed in to change notification settings - Fork 37
[4주차] RateLimit 적용 및 테스트 커버리지 개선 #85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
14ce595
74f84fa
620e443
44841c1
0103907
2fd597c
ed9e3f8
3aba743
e5c4f91
f6068e8
bf10709
47f4f76
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| package com.example.app.booking.service; | ||
|
|
||
| import com.example.app.booking.domain.Booking; | ||
| import com.example.app.booking.dto.CreateBookingCommand; | ||
| import com.example.app.booking.out.persistence.adapter.BookingPersistenceAdapter; | ||
| import com.example.app.booking.out.persistence.adapter.SeatPersistenceAdapter; | ||
| import com.example.app.common.exception.APIException; | ||
| import com.example.app.common.function.DistributedLockService; | ||
| import com.example.app.config.EmbeddedRedisConfig; | ||
| import com.example.app.movie.type.TheaterSeat; | ||
| import com.navercorp.fixturemonkey.FixtureMonkey; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.mockito.InjectMocks; | ||
| import org.mockito.Mock; | ||
| import org.springframework.boot.test.context.SpringBootTest; | ||
| import org.springframework.test.context.TestPropertySource; | ||
|
|
||
| import java.time.LocalDate; | ||
| import java.util.Set; | ||
| import java.util.function.Supplier; | ||
|
|
||
| import static com.example.app.booking.exception.BookingErrorMessage.SEAT_ROW_NOT_IN_SEQUENCE; | ||
| import static com.navercorp.fixturemonkey.api.instantiator.Instantiator.constructor; | ||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| import static org.junit.jupiter.api.Assertions.assertThrows; | ||
| import static org.mockito.Mockito.*; | ||
|
|
||
| @SpringBootTest(classes = EmbeddedRedisConfig.class) | ||
| @TestPropertySource(properties = "spring.config.location = classpath:application-test.yml") | ||
| public class CreateBookingServiceTest { | ||
|
|
||
| @Mock | ||
| private DistributedLockService distributedLockService; | ||
|
|
||
| @Mock | ||
| private BookingPersistenceAdapter bookingPersistenceAdapter; | ||
|
|
||
| @Mock | ||
| private SeatPersistenceAdapter seatPersistenceAdapter; | ||
|
|
||
| @InjectMocks | ||
| private CreateBookingService createBookingService; | ||
|
|
||
| @Test | ||
| public void 예약_테스트() { | ||
| var key = FixtureMonkey.create().giveMeOne(String.class); | ||
|
|
||
| var bookingCommand = FixtureMonkey.create() | ||
| .giveMeBuilder(CreateBookingCommand.class) | ||
| .instantiate(constructor() | ||
| .parameter(long.class) | ||
| .parameter(long.class) | ||
| .parameter(long.class) | ||
| .parameter(long.class) | ||
| .parameter(LocalDate.class) | ||
| .parameter(Set.class)) | ||
| .set("seats", Set.of(TheaterSeat.A3, TheaterSeat.A4, TheaterSeat.A5)) | ||
| .sample(); | ||
|
|
||
| var booking = FixtureMonkey.create() | ||
| .giveMeBuilder(Booking.class) | ||
| .instantiate(constructor() | ||
| .parameter(long.class) | ||
| .parameter(long.class) | ||
| .parameter(long.class) | ||
| .parameter(long.class) | ||
| .parameter(long.class) | ||
| .parameter(int.class) | ||
| .parameter(LocalDate.class)) | ||
| .set("totalSeats", 3) | ||
| .sample(); | ||
|
|
||
| when(distributedLockService.executeWithLockAndReturn(any(Supplier.class), any(String.class), any(Long.class), any(Long.class))) | ||
| .thenReturn(booking); | ||
|
|
||
| var result = createBookingService.createBooking(key, bookingCommand); | ||
|
|
||
| assertEquals(booking, result); | ||
| } | ||
|
|
||
| @Test | ||
| public void 예약_불가_테스트() { | ||
| var key = FixtureMonkey.create().giveMeOne(String.class); | ||
|
|
||
| var bookingCommand = FixtureMonkey.create() | ||
| .giveMeBuilder(CreateBookingCommand.class) | ||
| .instantiate(constructor() | ||
| .parameter(long.class) | ||
| .parameter(long.class) | ||
| .parameter(long.class) | ||
| .parameter(long.class) | ||
| .parameter(LocalDate.class) | ||
| .parameter(Set.class)) | ||
| .set("seats", Set.of(TheaterSeat.B1, TheaterSeat.C1, TheaterSeat.D1)) | ||
| .sample(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Set.of(TheaterSeat.B1, TheaterSeat.C1, TheaterSeat.D1) 부분을 불연속적인 좌석 을 의미하는 변수로 추출하여 전달하면 유지보수성 및 가독성이 더 좋아질 것 같습니다. |
||
|
|
||
| var exception = assertThrows(APIException.class, () -> createBookingService.createBooking(key, bookingCommand)); | ||
| assertEquals(exception.getMessage(), SEAT_ROW_NOT_IN_SEQUENCE.getMessage()); | ||
| } | ||
| } | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package com.example.app.config; | ||
|
|
||
| import jakarta.annotation.PreDestroy; | ||
| import jakarta.annotation.PostConstruct; | ||
| import org.springframework.boot.autoconfigure.data.redis.RedisProperties; | ||
| import org.springframework.boot.test.context.TestConfiguration; | ||
| import redis.embedded.RedisServer; | ||
|
|
||
| import java.io.IOException; | ||
|
|
||
| @TestConfiguration | ||
| public class EmbeddedRedisConfig { | ||
|
|
||
| private final RedisServer redisServer; | ||
|
|
||
| public EmbeddedRedisConfig(RedisProperties redisProperties) throws IOException { | ||
| this.redisServer = new RedisServer(redisProperties.getPort()); | ||
| } | ||
|
|
||
| @PostConstruct | ||
| public void postConstruct() throws IOException { | ||
| redisServer.start(); | ||
| } | ||
|
|
||
| @PreDestroy | ||
| public void preDestroy() throws IOException { | ||
| redisServer.stop(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| package com.example.app.movie.service; | ||
|
|
||
| import com.example.app.config.EmbeddedRedisConfig; | ||
| import com.example.app.movie.domain.Movie; | ||
| import com.example.app.movie.domain.Showtime; | ||
| import com.example.app.movie.domain.Theater; | ||
| import com.example.app.movie.dto.SearchMovieCommand; | ||
| import com.example.app.movie.out.persistence.adapter.MoviePersistenceAdapter; | ||
| import com.example.app.movie.type.MovieGenre; | ||
| import com.example.app.movie.type.MovieRating; | ||
| import com.example.app.movie.type.MovieStatus; | ||
| import com.navercorp.fixturemonkey.FixtureMonkey; | ||
| import com.navercorp.fixturemonkey.api.type.TypeReference; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.mockito.InjectMocks; | ||
| import org.mockito.Mock; | ||
| import org.springframework.boot.test.context.SpringBootTest; | ||
| import org.springframework.test.context.TestPropertySource; | ||
|
|
||
| import java.time.LocalDate; | ||
| import java.util.List; | ||
|
|
||
| import static com.navercorp.fixturemonkey.api.instantiator.Instantiator.constructor; | ||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| import static org.mockito.ArgumentMatchers.any; | ||
| import static org.mockito.Mockito.*; | ||
|
|
||
| @SpringBootTest(classes = EmbeddedRedisConfig.class) | ||
| @TestPropertySource(properties = "spring.config.location = classpath:application-test.yml") | ||
| public class SearchMovieServiceTest { | ||
|
|
||
| @Mock | ||
| private MoviePersistenceAdapter moviePersistenceAdapter; | ||
|
|
||
| @InjectMocks | ||
| private SearchMovieService searchMovieService; | ||
|
|
||
| @Test | ||
| public void 영화_검색() { | ||
| var searchCommand = FixtureMonkey.create() | ||
| .giveMeBuilder(SearchMovieCommand.class) | ||
| .instantiate(constructor() | ||
| .parameter(String.class) | ||
| .parameter(MovieGenre.class)) | ||
| .sample(); | ||
|
|
||
| var movies = FixtureMonkey.create() | ||
| .giveMeBuilder(Movie.class) | ||
| .instantiate(constructor() | ||
| .parameter(long.class) | ||
| .parameter(String.class) | ||
| .parameter(String.class) | ||
| .parameter(MovieStatus.class) | ||
| .parameter(MovieRating.class) | ||
| .parameter(MovieGenre.class) | ||
| .parameter(String.class) | ||
| .parameter(int.class) | ||
| .parameter(LocalDate.class) | ||
| .parameter(new TypeReference<List<Showtime>>(){}) | ||
| .parameter(new TypeReference<List<Theater>>(){})) | ||
| .sampleList(10); | ||
|
|
||
| when(moviePersistenceAdapter.loadAllMovies(any(SearchMovieCommand.class))).thenReturn(movies); | ||
|
|
||
| var result = searchMovieService.searchMovies(searchCommand); | ||
|
|
||
| assertEquals(10, result.size()); | ||
|
||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테스트 대상을 SUT(System Under Test) 이라고 부르는데, 실무에서는 테스트 대상을 코드 내에서 빠르게 식별하기 위해서 sut 이라는 네이밍도 자주 사용합니다.