λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

Spring

ν…ŒμŠ€νŠΈμ˜ μ’…λ₯˜, μŠ€ν”„λ§ ν…ŒμŠ€νŠΈ ν”„λ ˆμž„μ›Œν¬

ν…ŒμŠ€νŠΈμ˜ μ’…λ₯˜, μŠ€ν”„λ§ ν…ŒμŠ€νŠΈ ν”„λ ˆμž„μ›Œν¬

슀파λ₯΄νƒ€ μ½”λ”© 클럽의 Spring μ‹¬ν™”λ°˜ 3μ£Ό μ°¨ λ‚΄μš©μΈ ν…ŒμŠ€νŠΈμ˜ μ’…λ₯˜, μŠ€ν”„λ§ ν…ŒμŠ€νŠΈ ν”„λ ˆμž„μ›Œν¬μ„ μ •λ¦¬ν•œλ‹€.

핡심 λ‚΄μš©

  • ν…ŒμŠ€νŠΈμ˜ μ’…λ₯˜
  • μŠ€ν”„λ§ ν…ŒμŠ€νŠΈ ν”„λ ˆμž„μ›Œν¬ 이해 & μ‚¬μš©

ν…ŒμŠ€νŠΈμ˜ μ’…λ₯˜ & ν•„μš”μ„±

  • λΈ”λž™λ°•μŠ€ ν…ŒμŠ€νŠΈ : λ‚΄λΆ€μ˜ ꡬ쑰 및 λ™μž‘ 원리λ₯Ό λͺ¨λ₯΄λŠ” λΈ”λž™λ°•μŠ€μ™€ 같은 μƒνƒœ(μ„œλΉ„μŠ€μ˜ μ‚¬μš©μž μž…μž₯)μ—μ„œ λ™μž‘μ„ κ²€μ‚¬ν•˜λŠ” ν…ŒμŠ€νŠΈ 방법
    • μž₯점 : λˆ„κ΅¬λ‚˜ ν…ŒμŠ€νŠΈ κ°€λŠ₯
    • 단점 : κΈ°λŠ₯이 μΆ”κ°€λ μˆ˜λ‘ ν…ŒμŠ€νŠΈμ˜ λ²”μœ„κ°€ λŠ˜μ–΄λ‚˜κ³  ν…ŒμŠ€νŠΈν•˜λŠ” μ‚¬λžŒμ΄ λŠ˜μ–΄λ‚˜μ•Ό ν•œλ‹€.
  • 개발자 ν…ŒμŠ€νŠΈ : κ°œλ°œμžκ°€ μž‘μ„±ν•œ μ½”λ“œλ₯Ό 검증해 μ£ΌλŠ” ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό 직접 μž‘μ„±ν•˜λŠ” 방법
    • μž₯점 : λΉ λ₯΄κ³  μ •ν™•ν•œ ν…ŒμŠ€νŠΈ, μžλ™ν™” κ°€λŠ₯, κΈ°μ‘΄ μ½”λ“œκ°€ 잘 λ™μž‘ν•˜λŠ”μ§€ 확인할 수 있음, 배포 μ‹œμ— 항상 검증이 κ°€λŠ₯ν•˜λ‹€.
    • 단점 : 개발 μ‹œκ°„μ΄ 였래 걸리고, ν…ŒμŠ€νŠΈ μ½”λ“œμ˜ μœ μ§€ 보수 λΉ„μš©μ΄ λ“ λ‹€.
    • μŠ€ν”„λ§μ—μ„  JUnit을 μ΄μš©ν•œ λ‹¨μœ„ ν…ŒμŠ€νŠΈ, 톡합 ν…ŒμŠ€νŠΈκ°€ μžˆλ‹€.

μŠ€ν”„λ§ ν…ŒμŠ€νŠΈ ν”„λ ˆμž„μ›Œν¬ 이해 & μ‚¬μš©

λ‹¨μœ„ ν…ŒμŠ€νŠΈ

  • ν”„λ‘œκ·Έλž¨μ„ μž‘μ€ λ‹¨μœ„(클래슀, λͺ¨λ“ˆ, λ©”μ„œλ“œ λ“±..)으둜 μͺΌκ°œμ„œ 각 λ‹¨μœ„κ°€ μ •ν™•νžˆ λ™μž‘ν•˜λŠ”μ§€ κ²€μ‚¬ν•˜λŠ” ν…ŒμŠ€νŠΈ
  • μŠ€ν”„λ§μ—μ„  μžλ°” ν”„λ‘œκ·Έλž˜λ° μ–Έμ–΄μš© λ‹¨μœ„ ν…ŒμŠ€νŠΈ ν”„λ ˆμž„μ›Œν¬μΈ JUnit을 μ‚¬μš©ν•˜μ—¬ λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό μ‹€ν–‰ν•œλ‹€.
  • ν…ŒμŠ€νŠΈλ₯Ό μ›ν•˜λŠ” 클래슀, λ©”μ†Œλ“œλ₯Ό μœ„ν•œ νŒŒμΌμ„ λ§Œλ“  ν›„, ν…ŒμŠ€νŠΈν•  λ©”μ†Œλ“œμ— @Test, @DisplayName("...") λ“±μ˜ μ–΄λ…Έν…Œμ΄μ…˜μ„ 뢙인닀.
  • μœ„μ˜ μ–΄λ…Έν…Œμ΄μ…˜μ΄ λΆ™μ—¬μ Έ μžˆλŠ” λ©”μ†Œλ“œμ— Run 'ν•΄λ‹Ή λ©”μ†Œλ“œ()'의 κΈ°λŠ₯을 μ‹€ν–‰ν•˜λ©΄ ν…ŒμŠ€νŠΈκ°€ μ‹€ν–‰λœλ‹€.
  • ν…ŒμŠ€νŠΈ μ½”λ“œλŠ” 보톡 given(주어진 상황), when(ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•œ μ‹€ν–‰), then(κ²°κ³Ό)둜 λ‚˜λˆ μ„œ μž‘μ„±ν•œλ‹€.
  • 결괏값은 assertNull, assertEquals, assertFalseλ“±μ˜ λ©”μ†Œλ“œμ— νŒŒλΌλ―Έν„°λ₯Ό λ„£μ–΄ ν™•μΈν•œλ‹€.
  • μ˜ˆμ™Έ 처리의 κ²½μš°μ—” λ‹€μŒκ³Ό 같이 ν™•μΈν•œλ‹€.
// μ˜ˆμ™Έμ²˜λ¦¬ example

// when
Exception exception = assertThrows(IllegalArgumentException.class, () -> {
                        new Product(requestDto, userId);
                    });
// then
assertEquals("μƒν’ˆ μ΅œμ €κ°€κ°€ 0 μ΄ν•˜μž…λ‹ˆλ‹€.", exception.getMessage());
  • @Nested : 클래슀 μ•ˆμ— 클래슀λ₯Ό 넣을 수 있게 ν•΄μ£ΌλŠ” μ–΄λ…Έν…Œμ΄μ…˜μœΌλ‘œ ν…ŒμŠ€νŠΈ μ½”λ“œ κ²°κ³Όλ₯Ό 확인할 λ•Œ ν•˜μœ„ ꡬ쑰둜 ν‘œμ‹œλœλ‹€.

TDD(Test-Driven Development)

기쑴의 μˆœμ„œμΈ

섀계 -> 개발 -> ν…ŒμŠ€νŠΈ (-> 섀계 μˆ˜μ •)

의 μˆœμ„œλ₯Ό

섀계 -> ν…ŒμŠ€νŠΈ (->섀계 μˆ˜μ •) -> 개발

둜 λ³€κ²½ν•˜μ—¬ κ°œλ°œν•˜λŠ” 방법

즉, κ°œλ°œμ„ λ¨Όμ €ν•˜κΈ° 전에 ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό λ§Œλ“  ν›„ ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό 톡과할 수 μžˆλ„λ‘ κ°œλ°œν•˜λŠ” 방식이닀.

Mock object (κ°€μ§œ 객체)

λ‹¨μœ„ ν…ŒμŠ€νŠΈμ—μ„œ 각 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λŠ” μ„œλ‘œ λΆ„λ¦¬λ˜λŠ” 것이 이상적이기 λ•Œλ¬Έμ— κ°€μ§œ 객체λ₯Ό μƒμ„±ν•˜μ—¬ μ‚¬μš©ν•œλ‹€.

  • λ™μΌν•œ 클래슀λͺ…κ³Ό λ©”μ†Œλ“œλͺ… μ‚¬μš©
  • Mock 객체의 λ‚΄λΆ€ λ‘œμ§μ€ μ€‘μš”ν•˜μ§€ μ•Šλ‹€.
  • κ°œλ°œμžκ°€ Mock object ν•¨μˆ˜λ₯Ό ν…ŒμŠ€νŠΈ μ‹œλ‚˜λ¦¬μ˜€ λ³„λ‘œ 섀정이 κ°€λŠ₯ν•˜λ‹€.

Mockito mock을 μ΄μš©ν•œ λ‹¨μœ„ ν…ŒμŠ€νŠΈ

κ°œλ°œμžκ°€ 일일이 Mock objectλ₯Ό κ΅¬ν˜„ν•  수 μ—†κΈ° λ•Œλ¬Έμ— Mockitoλ₯Ό μ‚¬μš©ν•˜μ—¬ λ‹¨μœ„ ν…ŒμŠ€νŠΈλ₯Ό λ§Œλ“€κ³  ν•¨μˆ˜λ₯Ό ν…ŒμŠ€νŠΈ μ‹œλ‚˜λ¦¬μ˜€ λ³„λ‘œ μ„€μ •ν•œλ‹€.

μ˜ˆμ‹œ
  • @Mock μ–΄λ…Έν…Œμ΄μ…˜μ„ λΆ™μ—¬ ν•΄λ‹Ή 객체가 Mock object μž„μ„ λͺ…μ‹œν•œλ‹€.
  • when, thenReturn λ©”μ†Œλ“œλ₯Ό ν™œμš©ν•΄ μ‹œλ‚˜λ¦¬μ˜€λ₯Ό μ„€μ •ν•œλ‹€.
    • λͺ© 였브젝트의 μ •μ˜ : μ‚¬μš©μžμ˜ ν–‰μœ„λ₯Ό μ‘°κ±΄λΆ€λ‘œ 사전에 μž…λ ₯해두면, κ·Έ 상황에 μ˜ˆμ •λœ ν–‰μœ„λ₯Ό μˆ˜ν–‰ν•˜λŠ” 객체
  @ExtendWith(MockitoExtension.class)
  class ProductServiceTest {
      @Mock
      ProductRepository productRepository;

      // μƒλž΅ ...

      when(productRepository.findById(productId))
        .thenReturn(Optional.of(product));
  }

톡합 ν…ŒμŠ€νŠΈ

  • λͺ¨λ“ˆ 간에 μƒν˜Έ μž‘μš© 검증을 λͺ»ν•˜λŠ” λ‹¨μœ„ ν…ŒμŠ€νŠΈμ˜ ν•œκ³„λ₯Ό κ·Ήλ³΅ν•˜κΈ° μœ„ν•΄ 톡합 ν…ŒμŠ€νŠΈλ₯Ό μ‹€ν–‰
  • 두 개 μ΄μƒμ˜ λͺ¨λ“ˆμ΄ μ—°κ²°λœ μƒνƒœμ—μ„œ ν…ŒμŠ€νŠΈν•˜λ©°, λͺ¨λ“ˆ κ°„μ˜ μ—°κ²°μ—μ„œ λ°œμƒν•˜λŠ” μ—λŸ¬λ₯Ό κ²€μ¦ν•œλ‹€.
    • ex) Controller -> Service -> Repositoryκ°€ μ—°κ²°λœ ν•˜λ‚˜μ˜ ν†΅ν•©λœ ν…ŒμŠ€νŠΈλ₯Ό μˆ˜ν–‰
  • @SpringBootTest : μŠ€ν”„λ§ λΆ€νŠΈκ°€ μ œκ³΅ν•˜λŠ” ν…ŒμŠ€νŠΈ μ–΄λ…Έν…Œμ΄μ…˜μœΌλ‘œ, μŠ€ν”„λ§ IoC, DB CRUDλ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„  μ„ μ–Έν•΄μ€˜μ•Ό ν•œλ‹€.
  • @Order(N) : νŒŒλΌλ―Έν„° μ•ˆμ— 숫자λ₯Ό λ„£μ–΄ ν…ŒμŠ€νŠΈμ˜ μˆœμ„œλ₯Ό μ •ν•  수 μžˆλŠ” μ–΄λ…Έν…Œμ΄μ…˜