๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
โœ๏ธ Today I Learned(TIL)/์ŠคํŒŒ๋ฅดํƒ€ ๋‚ด์ผ๋ฐฐ์›€์บ ํ”„

[ TIL ] ์ตœ์ข… ํ”„๋กœ์ ํŠธ_Day 11

by carrot0911 2025. 2. 21.

์˜ค๋Š˜ ์ง„ํ–‰ํ•œ ๋‚ด์šฉ๋“ค ๐Ÿง 

Elasticsearch ๊ธฐ๊ฐ„ ๊ฒ€์ƒ‰ ์กฐํšŒ ์„ฑ๋Šฅ ๋น„๊ตํ•˜๊ธฐ

hiringStartAt๊ณผ hiringEndAt์„ ํ†ตํ•ด ์ฑ„์šฉ ๊ณต๊ณ ๋ฅผ ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์— Elasticsearch๋ฅผ ์ ์šฉํ–ˆ์„ ๋•Œ ์„ฑ๋Šฅ์ด ์–ผ๋งˆ๋‚˜ ํ–ฅ์ƒ๋˜๋Š”์ง€ ํ™•์ธํ•ด๋ดค๋‹ค. 
Elasticsearch๋ฅผ ์ ์šฉํ•˜๊ธฐ ์ „ํ›„์˜ ์†๋„๋ฅผ JMeter๋ฅผ ์ด์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ๋น„๊ตํ•ด ๋ณด์•˜๋‹ค.
100๊ฐœ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , 10์ดˆ ๋™์•ˆ 10ํšŒ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ด 1,000๊ฐœ์˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค.

Elasticsearch ์ ์šฉํ•˜๊ธฐ ์ „ ์„ฑ๋Šฅ
Elasticsearch ์ ์šฉํ•œ ํ›„ ์„ฑ๋Šฅ

Elasticsearch ์ ์šฉํ•˜๊ธฐ ์ „ํ›„ ์†๋„๊ฐ€ ์ฐจ์ด๊ฐ€ ๋ˆˆ์— ๋„๊ฒŒ ์ค„์–ด๋“  ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ ์šฉํ•˜๊ธฐ ์ „์—๋Š” 8ms์˜€๋Š”๋ฐ, Elasticsearch๋ฅผ ์ ์šฉํ•˜๊ณ  ๋‚˜๋‹ˆ 1ms๊นŒ์ง€ ๋–จ์–ด์กŒ๋‹ค.

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๊ณต๋ถ€ํ•˜๊ธฐ

์•„์ง ๊ณผ์ œ์—์„œ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ๋งŒ ํ•ด๋ณด๊ณ  ์‹ค์ œ๋กœ ๋‚ด๊ฐ€ ์ง์ ‘ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์งœ๋ณธ ๊ฒฝํ—˜์ด ์—†์–ด์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด ๊ด€๋ จ ๊ฐœ๋…๋“ค์„ ๊ณต๋ถ€ํ–ˆ๋‹ค. @Mock, @InjectMocks์™€ ๊ฐ™์€ ์–ด๋…ธํ…Œ์ด์…˜์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ•˜๊ณ  when์„ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ์ฝ”๋“œ๋ฅผ ์–ด๋–ค ์‹์œผ๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š”์ง€ ํ™•์ธํ–ˆ๋‹ค.

historyscheduler ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ

๋”๋ณด๊ธฐ
@ExtendWith(MockitoExtension.class)
public class historySchedulerTest {

    @InjectMocks
    private HistoryScheduler historyScheduler;

    @Mock
    private HistoryRepository historyRepository;

    @Mock
    private UserFindByService userFindByService;

    @Mock
    private RedisTemplate<String, String> redisTemplate;

    @Mock
    private ZSetOperations<String, String> zSetOperations;

    @Test
    void saveSearchHistoryToDb_์ •์ƒ์ ์œผ๋กœ_๋™์ž‘ํ• _๊ฒฝ์šฐ() {
        // given
        String key = "user:1:search_history";
        Set<String> keys = Set.of(key);
        Set<String> searchTerms = Set.of("Redis", "Java");

        when(redisTemplate.keys("user:*:search_history")).thenReturn(keys);
        when(redisTemplate.opsForZSet()).thenReturn(zSetOperations);
        when(zSetOperations.range(key, 0, -1)).thenReturn(searchTerms);

        User mockUser = User.of(
            "test@example.com",
            "testUser",
            25,
            3,
            "password123"
        );
        when(userFindByService.findById(1L)).thenReturn(mockUser);

        when(historyRepository.existsByUserIdAndName(1L, "Redis")).thenReturn(false);
        when(historyRepository.existsByUserIdAndName(1L, "Java")).thenReturn(true);

        // when
        historyScheduler.saveSearchHistoryToDb();

        // then
        verify(historyRepository,times(1)).save(any(History.class));
    }

    @Test
    void saveSearchHistoryToDb_์ €์žฅํ• _๊ฒ€์ƒ‰์–ด๊ฐ€_์—†์„_๊ฒฝ์šฐ() {
        // given
        String key = "user:1:search_history";
        Set<String> keys = Set.of(key);

        when(redisTemplate.keys("user:*:search_history")).thenReturn(keys);
        when(redisTemplate.opsForZSet()).thenReturn(zSetOperations);
        when(zSetOperations.range(key, 0, -1)).thenReturn(Collections.emptySet());

        // when
        historyScheduler.saveSearchHistoryToDb();

        // then
        verify(historyRepository, never()).save(any(History.class));
    }

    @Test
    void saveSearchHistoryToDb_์œ ์ €๊ฐ€_์—†์„_๊ฒฝ์šฐ_์˜ˆ์™ธ_๋ฐœ์ƒ() {
        // given
        String key = "user:99:search_history";
        Set<String> keys = Set.of(key);

        when(redisTemplate.keys("user:*:search_history")).thenReturn(keys);
        when(userFindByService.findById(99L)).thenThrow(new NotFoundException(DataErrorCode.USER_NOT_FOUND));

        // when & then
        NotFoundException exception = assertThrows(NotFoundException.class, () -> historyScheduler.saveSearchHistoryToDb());
        assertEquals(DataErrorCode.USER_NOT_FOUND.getMessage(), exception.getMessage());
        verify(historyRepository, never()).save(any(History.class));
    }
}

 

์˜ค๋Š˜ ํ•˜๋ฃจ ์ •๋ฆฌ โœ๏ธ

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ•˜๋‹ค ๋ณด๋‹ˆ ์•ฝ๊ฐ„ ์ดํ•ด๋ฅผ ํ•  ์ˆ˜ ์žˆ์„ ์ •๋„๊นŒ์ง„ ์ดํ•ด๋ ฅ์ด ์˜ฌ๋ผ์˜จ ๊ฒƒ ๊ฐ™๋‹ค.
์•„์ง ๊ณต๋ถ€ํ•ด์•ผ ํ•  ๊ฒƒ๋“ค์ด ์‚ฐ๋”๋ฏธ์ฒ˜๋Ÿผ ์Œ“์—ฌ์žˆ๋‹ค.

 

๋‚ด์ผ ๊ณ„ํš โฐ

  • V3 ํšŒ์˜ํ•˜๊ธฐ
  • Elasticsearch API ์—ฐ๋™ํ•˜๋Š” ๋ฐฉ๋ฒ• ํŠœํ„ฐ๋‹˜๊ป˜ ์ฐพ์•„๊ฐ€๊ธฐ

+ ์ถ”๊ฐ€ ๊ณ„ํš์ด ๋” ์ƒ๊ธธ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค!