Avatar
πŸ˜‰

Organizations

  • Rest APIλž€ 무엇이며, RestFul ν•˜λ‹€λŠ” 건 μ–΄λ–€ μ˜λ―ΈμΈκ°€?

    REST API와 RESTful의 κ°œλ…μ€ μ›Ή κ°œλ°œμ—μ„œ 자주 λ“±μž₯ν•˜μ§€λ§Œ, 처음 μ ‘ν•˜λ©΄ ν—·κ°ˆλ¦΄ 수 μžˆμ–΄μš”. μ‰½κ²Œ ν’€μ–΄μ„œ μ„€λͺ…ν•΄λ³Όκ²Œμš”.


    πŸ”Ή REST APIλž€?

    RESTλŠ” “REpresentational State Transfer"의 μ•½μžμ˜ˆμš”. 2000년에 둜이 ν•„λ”©(Roy Fielding)이 λ…Όλ¬Έμ—μ„œ μ œμ•ˆν•œ μ›Ή μ•„ν‚€ν…μ²˜ μŠ€νƒ€μΌ 쀑 ν•˜λ‚˜μ£ .

    즉, REST APIλŠ” 이 REST 원칙에 따라 μ„€κ³„λœ μ›Ή APIλ₯Ό λ§ν•΄μš”.


    πŸ”Ή REST의 핡심 κ°œλ…

    RESTλŠ” λ‹€μŒμ˜ 6κ°€μ§€ μ œμ•½ 쑰건을 기반으둜 ν•΄μš”:

    1. ν΄λΌμ΄μ–ΈνŠΈ-μ„œλ²„ ꡬ쑰

      • ν΄λΌμ΄μ–ΈνŠΈ(λΈŒλΌμš°μ €, μ•±)와 μ„œλ²„λŠ” μ„œλ‘œ λΆ„λ¦¬λ˜μ–΄ 역할을 λ‚˜λˆ”.
    2. λ¬΄μƒνƒœμ„± (Stateless)

    Created Thu, 03 Apr 2025 18:02:29 +0900
  • @Mockκ³Ό @MockBean은 λ‘˜ λ‹€ ν…ŒμŠ€νŠΈμ—μ„œ Mock 객체λ₯Ό λ§Œλ“€κΈ° μœ„ν•œ μ–΄λ…Έν…Œμ΄μ…˜μ΄μ§€λ§Œ, μ“°μ΄λŠ” ν™˜κ²½κ³Ό 역할이 쑰금 λ‹¬λΌμš”. κ°„λ‹¨νžˆ 차이뢀터 μš”μ•½ν•˜λ©΄:


    πŸ”Ή @Mock (from Mockito)

    • Mockitoμ—μ„œ μ œκ³΅ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜
    • **순수 λ‹¨μœ„ ν…ŒμŠ€νŠΈ(Unit Test)**에 μ‚¬μš©
    • Spring Contextμ™€λŠ” 무관
    • ν…ŒμŠ€νŠΈ 클래슀 λ‚΄μ—μ„œ μ˜μ‘΄μ„±μ„ Mock으둜 μ£Όμž…ν•˜κ³  싢을 λ•Œ μ‚¬μš©
    • MockitoAnnotations.openMocks(this) λ˜λŠ” @ExtendWith(MockitoExtension.class) 와 ν•¨κ»˜ μ‚¬μš©ν•΄μ•Ό 함

    μ˜ˆμ‹œ:

    @ExtendWith(MockitoExtension.class)
    class MyServiceTest {
    
        @Mock
        private MyRepository myRepository;
    
        @InjectMocks
        private MyService myService;
    
        @Test
        void testSomething() {
            // myRepositoryλŠ” mock 객체
        }
    }
    

    πŸ”Έ @MockBean (from Spring Boot)

    • Spring Boot Testμ—μ„œ μ œκ³΅ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜
    • 톡합 ν…ŒμŠ€νŠΈ(Integration Test) μ‹œ μ‚¬μš©
    • Spring ApplicationContext에 λ“±λ‘λœ Bean을 Mock으둜 ꡐ체
    • @SpringBootTest, @WebMvcTest, @DataJpaTest 같은 Spring 기반 ν…ŒμŠ€νŠΈ ν™˜κ²½μ—μ„œ μ‚¬μš©

    μ˜ˆμ‹œ:

    Created Thu, 03 Apr 2025 15:57:29 +0900
  • @Mock κ³Ό @InjectedMock

    @Mockκ³Ό @InjectMocks의 차이λ₯Ό μ•Œμ•„λ³Όκ²Œμš”. 이 λ‘˜μ€ ν•¨κ»˜ 자주 μ“°μ΄μ§€λ§Œ μ„œλ‘œ λ‹€λ₯Έ 역할을 ν•΄μš”.


    πŸ”Ή @Mock

    • Mockitoμ—μ„œ 제곡
    • Mock 객체λ₯Ό μƒμ„±ν•΄μ€Œ
    • λ‹¨λ…μœΌλ‘œλŠ” κ·Έλƒ₯ κ°€μ§œ 객체일 뿐, 아무 데도 μ£Όμž…λ˜μ§€ μ•ŠμŒ
    @Mock
    private MyRepository myRepository; // κ°€μ§œ 객체 생성
    

    πŸ”Έ @InjectMocks

    • μ—­μ‹œ Mockitoμ—μ„œ 제곡
    • ν…ŒμŠ€νŠΈ λŒ€μƒ 객체(ν…ŒμŠ€νŠΈν•  클래슀)λ₯Ό μƒμ„±ν•˜κ³ ,
      κ·Έ μ•ˆμ— μžˆλŠ” μ˜μ‘΄μ„± ν•„λ“œμ— @Mock으둜 λ§Œλ“  객체듀을 μžλ™μœΌλ‘œ μ£Όμž…
    @InjectMocks
    private MyService myService; // MyService 객체λ₯Ό λ§Œλ“€κ³ , 내뢀에 μžˆλŠ” MyRepository 등에 @Mock 객체λ₯Ό μ£Όμž…
    

    βœ… 간단 μ˜ˆμ‹œ

    @ExtendWith(MockitoExtension.class)
    class MyServiceTest {
    
        @Mock
        private MyRepository myRepository;
    
        @InjectMocks
        private MyService myService;
    
        @Test
        void testSomething() {
            // myServiceλŠ” μ‹€μ œ 객체
            // myRepositoryλŠ” mock 객체
            // myService λ‚΄λΆ€μ—μ„œ myRepositoryκ°€ μ‚¬μš©λ  λ•Œ mock이 μ£Όμž…λ¨
        }
    }
    

    πŸ“Œ μ •λ¦¬ν•˜μžλ©΄:

    μ–΄λ…Έν…Œμ΄μ…˜ μ—­ν• 
    @Mock κ°€μ§œ(Mock) 객체 생성
    @InjectMocks ν…ŒμŠ€νŠΈ λŒ€μƒ 객체λ₯Ό μƒμ„±ν•˜κ³ , @Mock 객체λ₯Ό κ·Έ μ•ˆμ— μ£Όμž…

    즉, @Mock이 κ°€μ§œ λΆ€ν’ˆμ„ λ§Œλ“œλŠ” κ±°κ³ ,
    @InjectMocksλŠ” κ·Έ λΆ€ν’ˆμ„ μ‘°λ¦½ν•΄μ„œ ν…ŒμŠ€νŠΈ λŒ€μƒ 객체λ₯Ό λ§Œλ“œλŠ” κ±°μ˜ˆμš”.

    Created Thu, 03 Apr 2025 15:57:29 +0900
  • Mock, Stub 의 차이

    mockκ³Ό stub은 ν…ŒμŠ€νŠΈμ—μ„œ μ™ΈλΆ€ μ˜μ‘΄μ„±μ„ λŒ€μ²΄ν•˜κΈ° μœ„ν•΄ μ“°μ΄λŠ” 객체인데, λ‘˜μ€ λͺ©μ κ³Ό κΈ°λŠ₯ λ©΄μ—μ„œ 쑰금 λ‹¬λΌμš”.


    πŸ“Œ μš”μ•½ 비ꡐ

    ν•­λͺ© Stub Mock
    λͺ©μ  κ³ μ •λœ κ°’ λ°˜ν™˜ (λ‹¨μˆœ λŒ€μ²΄) λ™μž‘ 검증 + μœ μ—°ν•œ μ„€μ •
    κΈ°λŠ₯ 미리 μ •μ˜λœ 응닡 제곡 호좜 μ—¬λΆ€, 호좜 횟수, νŒŒλΌλ―Έν„° 검증 λ“± κ°€λŠ₯
    ν…ŒμŠ€νŠΈ νƒ€μž… 주둜 μƒνƒœ 기반 ν…ŒμŠ€νŠΈ (State-based) 주둜 ν–‰μœ„ 기반 ν…ŒμŠ€νŠΈ (Behavior-based)
    μ˜ˆμ‹œ “이 λ©”μ„œλ“œκ°€ 호좜되면 무쑰건 이 값을 리턴” “이 λ©”μ„œλ“œκ°€ μ •ν™•νžˆ ν•œ 번 ν˜ΈμΆœλλŠ”μ§€ ν™•μΈν•˜μž”

    πŸ”Ή Stub: λ‹¨μˆœν•˜κ²Œ λ¦¬ν„΄κ°’λ§Œ 정해놓은 κ°€μ§œ

    • μ‹€μ œ λ©”μ„œλ“œ λ‘œμ§μ€ ν•„μš” μ—†κ³ , “이 값을 μ£Όλ©΄ 이 값을 돌렀쀘!” 같은 κ°„λ‹¨ν•œ λŒ€μ²΄ν’ˆ.
    • 주둜 “κΈ°μ‘΄ μ‹œμŠ€ν…œμ—μ„œ 이거만 μ œλŒ€λ‘œ λ™μž‘ν•˜λ©΄ 돼"λΌλŠ” ν…ŒμŠ€νŠΈμ— μ‚¬μš©.
    when(userRepository.findById(1L)).thenReturn(Optional.of(user));
    

    πŸ”Έ Mock: ν–‰μœ„(호좜 μ—¬λΆ€ λ“±)κΉŒμ§€ ν™•μΈν•˜λŠ” κ°€μ§œ

    • 리턴값도 μ •μ˜ν•  수 μžˆμ§€λ§Œ, “μ •λ§λ‘œ 이 λ©”μ„œλ“œκ°€ ν˜ΈμΆœλλŠ”κ°€?” 같은 검증도 κ°€λŠ₯.
    • verify() 같은 λ©”μ„œλ“œλ₯Ό 톡해 ν…ŒμŠ€νŠΈμ˜ 정확성을 λ†’μž„.
    verify(userRepository, times(1)).findById(1L);
    

    βœ… μ‹€μ œ ν…ŒμŠ€νŠΈ μ˜ˆμ‹œ

    @Mock
    UserRepository userRepository;
    
    @InjectMocks
    UserService userService;
    
    @Test
    void testUserFetch() {
        // Stub: 리턴값 μ§€μ •
        when(userRepository.findById(1L)).thenReturn(Optional.of(new User("Alice")));
    
        // λ©”μ„œλ“œ μ‹€ν–‰
        User user = userService.getUser(1L);
    
        // Mock: 호좜 μ—¬λΆ€ 검증
        verify(userRepository, times(1)).findById(1L);
    }
    

    πŸ“Ž 간단 λΉ„μœ 

    • Stub: β€œλˆ„κ°€ 와도 무쑰건 이 λŒ€μ‚¬λ§Œ 말해!”
    • Mock: β€œλˆ„κ°€ 였면 이 λŒ€μ‚¬λ₯Ό ν•˜κ³ , μ œλŒ€λ‘œ λ§ν–ˆλŠ”μ§€ 검사도 ν•©λ‹ˆλ‹€.!”

    Created Thu, 03 Apr 2025 15:57:29 +0900
  • ν…ŒμŠ€νŠΈ 더블(Test Double) μš©μ–΄ 정리

    • μ•„λž˜λŠ” ν…ŒμŠ€νŠΈμ—μ„œ 자주 μ“°μ΄λŠ” 5κ°€μ§€ ν…ŒμŠ€νŠΈ λŒ€μ—­μž…λ‹ˆλ‹€:

    πŸ§ͺ ν…ŒμŠ€νŠΈ 더블(Test Double) μ’…λ₯˜ μš”μ•½

    νƒ€μž… μ„€λͺ… 주둜 ν•˜λŠ” 일 λŒ€ν‘œ μ˜ˆμ‹œ
    Dummy 값이 ν•„μš”ν•˜μ§€λ§Œ 아무 역할도 ν•˜μ§€ μ•ŠλŠ” 객체 λ©”μ„œλ“œ μ‹œκ·Έλ‹ˆμ²˜ μ±„μš°κΈ° 용 new User(null)처럼 κ°’λ§Œ 채움
    Fake μ‹€μ œ κ΅¬ν˜„μ— κ°€κΉŒμš°λ‚˜, λ‹¨μˆœν•˜κ±°λ‚˜ in-memory 기반 κ°„λ‹¨ν•œ λŒ€μ²΄ κ΅¬ν˜„ InMemory DB, FakeEmailSender
    Stub κ³ μ •λœ 응닡을 λ¦¬ν„΄ν•˜λŠ” 객체 μƒνƒœ 기반 ν…ŒμŠ€νŠΈ when(repo.findById()).thenReturn()
    Mock ν–‰μœ„ 기반, 호좜 μ—¬λΆ€λ‚˜ μˆœμ„œ 검증이 κ°€λŠ₯ν•œ 객체 ν–‰μœ„ 기반 ν…ŒμŠ€νŠΈ verify(repo).save()
    Spy μ‹€μ œ 객체λ₯Ό κ°μ‹Έλ©΄μ„œ, λΆ€λΆ„μ μœΌλ‘œ mock κ°€λŠ₯ μ‹€μ œ λ™μž‘ + 호좜 κ°μ‹œ spy(new UserService(...))

    1. 🐣 Dummy

    • κ°€μž₯ λ‹¨μˆœν•œ ν˜•νƒœ.
    • 아무 일도 ν•˜μ§€ μ•Šκ³ , κ°’λ§Œ μ±„μš°λŠ” μš©λ„.
    • ν…ŒμŠ€νŠΈμ— 직접적 의미 μ—†μŒ. 없어도 ν…ŒμŠ€νŠΈ 톡과 κ°€λŠ₯.
    User dummyUser = new User(null); // μƒμ„±μž λ§€κ°œλ³€μˆ˜ λ§žμΆ”λ €κ³  λ„£λŠ” μš©λ„
    

    2. πŸ§ͺ Stub

    • ν˜ΈμΆœν•˜λ©΄ μ •ν•΄μ§„ 값을 리턴함.
    • λ™μž‘ μžμ²΄λŠ” λ‹¨μˆœν•˜κ³  검증 λ‘œμ§μ€ μ—†μŒ.
    • μƒνƒœ 기반 ν…ŒμŠ€νŠΈμ— μ‚¬μš©λ¨.
    when(userRepository.findById(1L)).thenReturn(Optional.of(new User("Alice")));
    

    3. πŸ€– Mock

    • Stub처럼 리턴값을 쀄 수 μžˆμ§€λ§Œ, μΆ”κ°€λ‘œ 호좜 여뢀도 검증함.
    • ν…ŒμŠ€νŠΈμ˜ **ν–‰μœ„ 검증(Behavior Verification)**에 초점.
    verify(userRepository, times(1)).save(any());
    

    4. πŸ•΅οΈ Spy

    • μ‹€μ œ 객체λ₯Ό κ°μ‹Έλ©΄μ„œ, ν•„μš”ν•œ λΆ€λΆ„λ§Œ mock 처리 κ°€λŠ₯.
    • 일뢀 λ©”μ„œλ“œλŠ” μ§„μ§œ μ‹€ν–‰, μΌλΆ€λŠ” stub/mock κ°€λŠ₯.
    • μ‚¬μš© μ‹œ 쑰심: μ§„μ§œ μ˜μ‘΄μ„±μ΄ λ”°λΌμ˜¬ 수 있음.
    UserService spyService = spy(new UserService(realRepository));
    doReturn("fakeName").when(spyService).getUserName();
    

    5. 🧩 Fake

    • μ§„μ§œ κ΅¬ν˜„μ²΄λŠ” μ•„λ‹ˆμ§€λ§Œ, μ‹€μ œλ‘œ λ™μž‘ν•˜λŠ” κ°„λ‹¨ν•œ κ΅¬ν˜„.
    • ν…ŒμŠ€νŠΈμš©μœΌλ‘œ κ°€λ³κ²Œ λ§Œλ“  μ§„μ§œ λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ„ 흉내낸 것.
    • 예: InMemory DB, ν…ŒμŠ€νŠΈμš© λ©”μ‹œμ§€ 큐 λ“±
    public class InMemoryUserRepository implements UserRepository {
        private Map<Long, User> db = new HashMap<>();
        public Optional<User> findById(Long id) { return Optional.ofNullable(db.get(id)); }
    }
    

    🎯 μ–΄λ–€ κ±Έ μ–Έμ œ 써야 ν• κΉŒ?

    ν…ŒμŠ€νŠΈ λͺ©μ  μ ν•©ν•œ 더블
    νŒŒλΌλ―Έν„° μ±„μš°κΈ°λ§Œ ν•˜λ©΄ 됨 Dummy
    κ³ μ •λœ κ°’ λ¦¬ν„΄λ§Œ ν•„μš” Stub
    호좜 μ—¬λΆ€/횟수 검증 Mock
    μ‹€μ œ 객체 + 일뢀 mocking Spy
    μ‹€μ œ κ΅¬ν˜„ λΉ„μŠ·ν•œ λ™μž‘ ν•„μš” Fake

    Fake Repository μ˜ˆμ‹œ

    Spring ν™˜κ²½μ—μ„œ 자주 μ“°μ΄λŠ” Fake Repository 예제λ₯Ό λ³΄μ—¬λ“œλ¦΄κ²Œμš”.
    λ‹¨μœ„ ν…ŒμŠ€νŠΈμ—μ„œ JPA 같은 μ‹€μ œ DB μ—°κ²° 없이도 λ‘œμ§μ„ κ²€μ¦ν•˜κ³  싢을 λ•Œ μ•„μ£Ό μœ μš©ν•©λ‹ˆλ‹€.

    Created Thu, 03 Apr 2025 15:57:29 +0900
  • MSA(Microservices Architecture)μ—μ„œ trace ID와 span IDλŠ” **λΆ„μ‚° 좔적(distributed tracing)**μ—μ„œ μ‚¬μš©λ˜λŠ” 고유 μ‹λ³„μžλ“€μ΄μ•Ό. μ‹œμŠ€ν…œ μ „μ²΄μ—μ„œ μš”μ²­μ˜ 흐름을 좔적할 수 있게 ν•΄μ£ΌλŠ” 핡심 κ°œλ…μž…λ‹ˆλ‹€.


    1. Trace ID

    • ν•˜λ‚˜μ˜ 전체 μš”μ²­(Request)을 μ‹λ³„ν•˜λŠ” κ³ μœ ν•œ IDμž…λ‹ˆλ‹€.
    • 예: μ‚¬μš©μžκ°€ μ›Ήμ—μ„œ μ–΄λ–€ λ²„νŠΌμ„ ν΄λ¦­ν•΄μ„œ API μš”μ²­μ΄ λ“€μ–΄μ˜€κ³ , κ·Έ μš”μ²­μ΄ μ—¬λŸ¬ 개의 λ§ˆμ΄ν¬λ‘œμ„œλΉ„μŠ€λ₯Ό 거쳐 μ²˜λ¦¬λ˜λŠ” 경우, 이 전체 흐름을 ν•˜λ‚˜μ˜ trace둜 λ΄…λ‹ˆλ‹€.
    • 즉, trace IDλŠ” **“이 μš”μ²­μ΄ μ–΄λ””μ„œ μ‹œμž‘λΌμ„œ μ–΄λ””κΉŒμ§€ κ°”λŠ”κ°€”**λ₯Ό λ‚˜νƒ€λƒ„.

    2. Span ID

    • trace μ•ˆμ—μ„œ **각각의 μž‘μ—… λ‹¨μœ„(μž‘μ€ 호좜 ν•˜λ‚˜ν•˜λ‚˜)**λ₯Ό μ‹λ³„ν•˜λŠ” IDμž…λ‹ˆλ‹€.
    • 예: A μ„œλΉ„μŠ€κ°€ B μ„œλΉ„μŠ€μ™€ C μ„œλΉ„μŠ€λ₯Ό ν˜ΈμΆœν•˜λ©΄, A-B, A-C 각각이 λ³„λ„μ˜ span이 되고, 각각에 λŒ€ν•œ span IDκ°€ μžˆμŠ΅λ‹ˆλ‹€.
    • Span은 μ‹œμž‘ μ‹œκ°„, μ’…λ£Œ μ‹œκ°„, μ–΄λ–€ μž‘μ—…μΈμ§€ λ“± μ„ΈλΆ€ 정보도 ν¬ν•¨λ©λ‹ˆλ‹€.

    ꡬ쑰 μ˜ˆμ‹œ

    [Trace ID: abc123]
    
       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
       β”‚ User Request│──────▢│ API Gateway │───┐
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
                                               β–Ό
                                       β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                       β”‚ Service A  │───┐
                                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
                                                        β–Ό
                                                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                                β”‚ Service B  β”‚
                                                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    
    • 전체 μš”μ²­μ˜ 흐름이 ν•˜λ‚˜μ˜ Trace ID (abc123)λ₯Ό κ³΅μœ ν•˜κ³ ,
    • 각 μ„œλΉ„μŠ€ κ°„ ν˜ΈμΆœμ€ μ„œλ‘œ λ‹€λ₯Έ Span IDλ₯Ό 가짐.

    μš”μ•½

    ν•­λͺ© μ„€λͺ…
    Trace ID 전체 μš”μ²­ 흐름을 μΆ”μ ν•˜κΈ° μœ„ν•œ 고유 ID
    Span ID Trace λ‚΄μ—μ„œ κ°œλ³„ μž‘μ—…μ„ κ΅¬λΆ„ν•˜λŠ” ID

    첨언

    • μ‹€μ œ MSA κ΅¬ν˜„μ‹œ front endμ—μ„œ api requestμ‹œμ λΆ€ν„° trace id와 span idκ°€ μ±„λ²ˆλ˜κ³ 
    • 예λ₯Ό λ“€μ–΄, bff -> api-gateway -> user-service λ₯Ό 톡해 request κ°€ ν˜λŸ¬κ°„λ‹€λ©΄, 각 μ„œλΉ„μŠ€λŠ” λ™μΌν•œ trace id둜 좔적이 λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.
    Created Wed, 02 Apr 2025 10:50:33 +0900