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

[ TIL ] ์ฃผํŠน๊ธฐ ์‹ฌํ™”_Day 8

by carrot0911 2025. 1. 6.

์˜ค๋Š˜ ํ•œ ๊ณต๋ถ€ ๐Ÿง 

  • ๊ฐœ์ธ ๊ณผ์ œ ๋ ˆ๋ฒจ 5 - 2๊นŒ์ง€ ๋งˆ๋ฌด๋ฆฌ ํ›„ ์ œ์ถœ
  • ๊ณผ์ œ ํ•ด์„ค ์„ธ์…˜ ๋“ฃ๊ธฐ
  • ์Šคํƒ ๋‹ค๋“œ๋ฐ˜ ์„ธ์…˜ ๋“ฃ๊ธฐ
  • ์ˆ˜๊ฐ•์ƒ ๋ฏธ๋‹ˆ ์„ธ์…˜ ๋“ฃ๊ธฐ
  • TIL ๋ธ”๋กœ๊ทธ ์ž‘์„ฑ

 

์˜ค๋Š˜ ์–ป์€ ๋‚ด์šฉ ์ •๋ฆฌ โœ๏ธ 

์Šคํƒ ๋‹ค๋“œ๋ฐ˜ ์„ธ์…˜ - AOP

AOP: ๊ด€์  ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค.
ํŠน์ •ํ•œ ๋„๋ฉ”์ธ์— ์ข…์†๋˜์ง€ ์•Š๊ณ  ๋‚ด๊ฐ€ ์–ด๋–ค ์‹œ์ ์— ์ผ๊ด„์ ์œผ๋กœ ๋ชจ๋‘ ์ ์šฉํ•ด์ฃผ๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
๊ณ„์‚ฐ๋œ ๊ฒฐ๊ณผ๊ฐ’์— ๋Œ€ํ•ด์„œ ์ถœ๋ ฅํ•ด ์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ → ๋ชจ๋‘๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” ๊ธฐ๋Šฅ → AOP๋กœ ๋งŒ๋“ค์–ด์„œ ์ถ”๊ฐ€ํ•˜๋ฉด ํŽธํ•˜๋‹ค.

๋Œ€ํ‘œ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ

  1. ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜์—ˆ๋Š”์ง€ ์‹คํ–‰๋˜์ง€ ์•Š์•˜๋Š”์ง€ ์ถœ๋ ฅํ•ด ์ฃผ๋Š” ๋กœ๊ทธ
  2. ๊ฐ๊ฐ์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ์–ผ๋งˆ๋‚˜ ๊ฑธ๋ ธ๋Š”์ง€ ์„ฑ๋Šฅ์„ ๊ตฌํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  3. ๊ถŒํ•œ ๊ฒ€์‚ฌํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์–ด๋–ค ๊ฒƒ์„? ์–ธ์ œ? ์–ด๋–ป๊ฒŒ? → ์ง€์ •ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

  • ๋Œ€์ƒ ์ง€์ • → PointCut์„ ํ†ตํ•ด์„œ ๋Œ€์ƒ์„ ์ง€์ •ํ•ด์ค€๋‹ค.
  • ์‹œ์  ์ง€์ • → Advice๋ฅผ ํ†ตํ•ด์„œ ์‹คํ–‰๋˜๋Š” ์‹œ์ ์„ ์ง€์ •ํ•ด ์ค€๋‹ค. ex) @Before, @After
  • ์–ด๋–ป๊ฒŒ๋Š” Advice๋กœ ์–ธ์ œ ์‹คํ–‰๋  ๊ฑด์ง€ ์ •์˜ํ•œ ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์— ์–ด๋–ป๊ฒŒ ์‹คํ–‰ํ•  ๊ฒƒ์ธ์ง€๋ฅผ ์ž‘์„ฑํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

์ข€ ๋” ๋””ํ…Œ์ผํ•˜๊ณ  ์‹ถ๋‹ค.

๋Œ€์ƒ์„ ์žก์•˜๋Š”๋ฐ ๊ทธ ๋Œ€์ƒ์— ๋Œ€ํ•ด์„œ ์ •๋ณด๋ฅผ ๋ฐ›๊ณ  ์‹ถ์„ ๋•Œ JoinPoint๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
๊ฐ๊ฐ์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์–ด๋–ค ๋ฉ”์„œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š”์ง€ ๋กœ๊ทธ๋ฅผ ์ฐ๊ณ  ์‹ถ๋‹ค. (์–ด๋–ค ๊ฒƒ์— ๋Œ€ํ•˜ ์ •๋ณด๋ฅผ ์–ป๊ณ  ์‹ถ๋‹ค. → JoinPoint๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.)
JoinPoint๋ฅผ ํ†ตํ•ด์„œ ์–ด๋–ค ๋ฉ”์„œ๋“œ๊ฐ€ ์–ด๋–ค ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

๊ฐœ์ธ ๊ณผ์ œ ๋ ˆ๋ฒจ 5 ๋„์ „

๋ ˆ๋ฒจ 5 - 1

@ExtendWith(SpringExtension.class)
class PasswordEncoderTest {

    @InjectMocks
    private PasswordEncoder passwordEncoder;

    @Test
    void ๋น„๋ฐ€๋ฒˆํ˜ธ_๊ฒ€์‚ฌ_์„ฑ๊ณต() {
        // given
        String rawPassword = "testPassword";
        String encodedPassword = passwordEncoder.encode(rawPassword);

        // when
        // matches ๋ฉ”์„œ๋“œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ˆœ์„œ๋Š” (์›๋ณธ ๋น„๋ฐ€๋ฒˆํ˜ธ, ์ธ์ฝ”๋”ฉ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ)์ด๋‹ค.
        // ๋”ฐ๋ผ์„œ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ์–ด์•ผ ํ•œ๋‹ค.
        boolean actualResult = passwordEncoder.matches(rawPassword, encodedPassword);

        // then
        // ๋ฐฉ๋ฒ• 1. isEqualTo ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๊ฐ’ ๋น„๊ตํ•˜๊ธฐ
        boolean expectedResult = true;
        assertThat(actualResult).isEqualTo(expectedResult);

        // ๋ฐฉ๋ฒ• 2. assertTrue ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด true์ธ์ง€ ํ™•์ธํ•˜๊ธฐ
        // assertTrue(actualResult);

    }
}

๋ ˆ๋ฒจ 5 - 2

  • 1๋ฒˆ ์ผ€์ด์Šค
    • NullPointerException์—์„œ InvalidRequestException์œผ๋กœ ์ˆ˜์ •
    • ์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ ๋ฉ”์‹œ์ง€ ์ˆ˜์ •
@Test
// NullPointerException์ด ์•„๋‹ˆ๋ผ InvalidRequestException์ด ๋ฐœ์ƒํ•œ๋‹ค.
public void manager_๋ชฉ๋ก_์กฐํšŒ_์‹œ_Todo๊ฐ€_์—†๋‹ค๋ฉด_InvalidRequestException_์—๋Ÿฌ๋ฅผ_๋˜์ง„๋‹ค() {
    // given
    long todoId = 1L;
    given(todoRepository.findById(todoId)).willReturn(Optional.empty());

    // when & then
    InvalidRequestException exception = assertThrows(InvalidRequestException.class, () -> managerService.getManagers(todoId));
    // ์ผ์ •์ด ์—†์„ ๋•Œ์˜ ์˜ˆ์™ธ ๋ฉ”์‹œ์ง€๋Š” "ํˆฌ๋‘ not found"์ด๋‹ค.
    assertEquals("Todo not found", exception.getMessage());
}
  • 2๋ฒˆ ์ผ€์ด์Šค
    • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ๋Š” ServerException์„ ๋˜์ง€๊ณ  ์žˆ๋Š”๋ฐ, ์‹ค์ œ ๋กœ์ง์—์„œ๋Š” InvalidReqeustException์„ ๋˜์ง€๊ณ  ์žˆ๋‹ค.
    • ์‹ค์ œ ๋กœ์ง์— ๋งž์ถฐ์„œ InvalidRequestException์œผ๋กœ ์ˆ˜์ •ํ–ˆ๋‹ค.
@Test
public void comment_๋“ฑ๋ก_์ค‘_ํ• ์ผ์„_์ฐพ์ง€_๋ชปํ•ด_์—๋Ÿฌ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() {
    // given
    long todoId = 1;
    CommentSaveRequest request = new CommentSaveRequest("contents");
    AuthUser authUser = new AuthUser(1L, "email", UserRole.USER);

    given(todoRepository.findById(anyLong())).willReturn(Optional.empty());

    // when
    // ์‹ค์ œ ์„œ๋น„์Šค ์ฝ”๋“œ์—์„œ InvalidRequestException๋ฅผ ๋˜์ง€๊ณ  ์žˆ๋‹ค.
    // ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์—์„œ๋„ ๋™์ผํ•˜๊ฒŒ InvalidRequestException์„ ์˜ˆ์ƒํ•˜๋„๋ก ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.
    InvalidRequestException exception = assertThrows(InvalidRequestException.class, () -> {
        commentService.saveComment(authUser, todoId, request);
    });

    // then
    assertEquals("Todo not found", exception.getMessage());
}
  • 3๋ฒˆ ์ผ€์ด์Šค
    • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์„ฑ๊ณตํ•  ์ˆ˜ ์žˆ๋„๋ก ์„œ๋น„์Šค ๋กœ์ง์„ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.
@Transactional
public ManagerSaveResponse saveManager(AuthUser authUser, long todoId, ManagerSaveRequest managerSaveRequest) {
    // ์ผ์ •์„ ๋งŒ๋“  ์œ ์ €
    User user = User.fromAuthUser(authUser);
    Todo todo = todoRepository.findById(todoId)
            .orElseThrow(() -> new InvalidRequestException("Todo not found"));

    if (ObjectUtils.nullSafeEquals(todo.getUser(), null)) {
        throw new InvalidRequestException("๋‹ด๋‹น์ž๋ฅผ ๋“ฑ๋กํ•˜๋ ค๊ณ  ํ•˜๋Š” ์œ ์ €๊ฐ€ ์ผ์ •์„ ๋งŒ๋“  ์œ ์ €๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
    }

    if (!ObjectUtils.nullSafeEquals(user.getId(), todo.getUser().getId())) {
        throw new InvalidRequestException("๋‹ด๋‹น์ž๋ฅผ ๋“ฑ๋กํ•˜๋ ค๊ณ  ํ•˜๋Š” ์œ ์ €๊ฐ€ ์ผ์ •์„ ๋งŒ๋“  ์œ ์ €๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
    }

    User managerUser = userRepository.findById(managerSaveRequest.getManagerUserId())
            .orElseThrow(() -> new InvalidRequestException("๋“ฑ๋กํ•˜๋ ค๊ณ  ํ•˜๋Š” ๋‹ด๋‹น์ž ์œ ์ €๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."));

    if (ObjectUtils.nullSafeEquals(user.getId(), managerUser.getId())) {
        throw new InvalidRequestException("์ผ์ • ์ž‘์„ฑ์ž๋Š” ๋ณธ์ธ์„ ๋‹ด๋‹น์ž๋กœ ๋“ฑ๋กํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
    }

    Manager newManagerUser = new Manager(managerUser, todo);
    Manager savedManagerUser = managerRepository.save(newManagerUser);

    return new ManagerSaveResponse(
            savedManagerUser.getId(),
            new UserResponse(managerUser.getId(), managerUser.getEmail())
    );
}

 

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

์˜ค๋Š˜์€ ๊ฐœ์ธ ๊ณผ์ œ ๋งˆ๋ฌด๋ฆฌํ•˜๊ณ  ์ œ์ถœํ•˜๋Š” ๋‚ ์ด์—ˆ๋‹ค.

์˜ค์ „๋™์•ˆ ๋ ˆ๋ฒจ 5์— ํ•ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„์ธ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋ฐ ์„œ๋น„์Šค ๋กœ์ง ์ˆ˜์ •์„ ๊ณ„์† ์ง„ํ–‰ํ–ˆ๋‹ค.
์ ์‹ฌ์‹œ๊ฐ„๊นŒ์ง€ ํ™œ์šฉํ•ด์„œ ๋ ˆ๋ฒจ 5 - 2๊นŒ์ง€ ๋๋‚ผ ์ˆ˜ ์žˆ์—ˆ๊ณ , ์˜คํ›„์—๋Š” ์„ธ์…˜์˜ ์—ฐ์†์ด์—ˆ๋‹ค.

๊ณผ์ œ ํ•ด์„ค ์„ธ์…˜์„ ์—ด์‹ฌํžˆ ๋“ค์€ ํ›„์— ์ด์–ด์„œ ์Šคํƒ ๋‹ค๋“œ๋ฐ˜ ์„ธ์…˜์„ ๋“ค์—ˆ๋‹ค.
์Šคํƒ ๋‹ค๋“œ๋ฐ˜ ์„ธ์…˜์˜ ์ฃผ์ œ๋Š” AOP์˜€๋Š”๋ฐ ํŠœํ„ฐ๋‹˜์ด ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋„๋ก ์„ค๋ช…ํ•ด ์ฃผ์…”์„œ @Around์˜ ๊ฐœ๋…์ด ๋“ค์–ด๊ฐ€๊ธฐ ์ „๊นŒ์ง€ ์ดํ•ด๊ฐ€ ์ž˜ ๋๋‹ค. ํ•˜์ง€๋งŒ ๋ฌธ์ œ๋Š” ๊ทธ ์ดํ›„์˜€๋‹ค... ๋ญ”๊ฐ€ ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด์„œ ๊ทธ๋ƒฅ ์ฝ”๋“œ๋ฅผ ๋”ฐ๋ผ์น˜๊ฒŒ ๋˜๋Š” ๋Š๋‚Œ์ด ๊ฐ•ํ•ด์กŒ๋‹ค... ๊ทธ๋ž˜์„œ ํŠœํ„ฐ๋‹˜์ด ๊ทธ๊ฑธ ์บ์น˜ํ•˜์‹œ๊ณ  ์„ธ์…˜์ด ๋๋‚œ ํ›„ ๋ณด์ถฉ ์„ธ์…˜์„ ํ†ตํ•ด ์ดํ•ด๊ฐ€ ๊ฐ€์ง€ ์•Š๋Š” ๋ถ€๋ถ„์„ ์ข€ ๋” ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•ด ์ฃผ์‹œ๋ฉด์„œ ์–ด๋Š ์ •๋„(?) ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.
ํ•˜์ง€๋งŒ ์ดํ•ด๋กœ ๋๋‚˜๋ฉด ์•ˆ ๋˜๋‹ˆ๊นŒ... ๋น ๋ฅธ ์‹œ๊ฐ„ ๋‚ด์— ๋‹ค์‹œ ๋ณต์Šตํ•˜๋ฉด์„œ ์‹ค์ œ๋กœ ๋‚ด๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๋Š” ์‹œ๊ฐ„๋„ ๊ฐ€์ ธ์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค.

๋‚ด์ผ์€ ๋“œ๋””์–ด ๋˜ ํŒ€ํ”„๋กœ์ ํŠธ ์‹œ์ž‘์ด๋‹ค!! ์–ด๋–ค ์ฃผ์ œ์˜ ํ”„๋กœ์ ํŠธ๊ฐ€ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์„์ง€... ๋‘๋ ต๊ธฐ๋„ ํ•˜์ง€๋งŒ ํ”„๋กœ์ ํŠธ๋ฅผ ํ†ตํ•ด ๋งŽ์ด ์„ฑ์žฅํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ๊นŒ ๊ธฐ๋Œ€๋„ ๋œ๋‹ค.
๋‚ด๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์—ญํ• ์€ ์ตœ๋Œ€ํ•œ ๋‹ด๋‹นํ•ด์„œ ๋น ๋ฅธ ๊ธฐ๊ฐ„ ๋‚ด์— ๋งŽ์ด ์„ฑ์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ๊ฐ„์ด ๋˜์—ˆ์œผ๋ฉด ์ข‹๊ฒ ๋‹ค.
์ด๋ฒˆ ํŒ€ ํ”„๋กœ์ ํŠธ๋„ ํŒŒ์ดํŒ… ํ•ด๋ณด์ž!!!!!!

 

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

  • ํŒ€ํ”„๋กœ์ ํŠธ ์‹œ์ž‘
  • TIL ๋ธ”๋กœ๊ทธ ์ž‘์„ฑ

+์ถ”๊ฐ€ ๊ณ„ํš์ด ๋” ์ƒ๊ธธ ์ˆ˜๋„ ์žˆ์Šด๋‹น~_~