TDD-02
π ν μ€νΈ λλΈ (Test Double): Mockκ³Ό Stub
ν μ€νΈ λλΈ(Test Double)μ μ€μ κ°μ²΄(Real Object)λ₯Ό λμ νμ¬ ν μ€νΈλ₯Ό μν΄ μ¬μ©λλ λͺ¨λ μ’ λ₯μ λμ κ°μ²΄λ₯Ό μλ―Έν©λλ€. μΈλΆ μμ€ν (DB, API λ±)μ λν μμ‘΄μ±μ μ κ±°νμ¬ λ 립μ μ΄κ³ , λΉ λ₯΄λ©°, μ λ’°μ± λμ ν μ€νΈ νκ²½μ ꡬμΆνλ λ° ν΅μ¬μ μΈ μν μ ν©λλ€.
κ·Έμ€ κ°μ₯ λνμ μΈ κ²μ΄ Mockκ³Ό Stubμ λλ€.
- Mock (νμ κ²μ¦)
νΉμ ν¨μκ° νΈμΆλμλμ§, μ ν΄μ§ νλμ μννλμ§ κ²μ¦νλ λ° μ¬μ©λλ©°, κ°μ²΄μ νλ(Behavior)μ μ΄μ μ λ§μΆ₯λλ€.
μμ:
verify(mockRepository, times(1)).save(any(User.class));
μ κ°μ΄save
λ©μλκ° 1λ² νΈμΆλμλμ§ κ²μ¦ν©λλ€. - Stub (μν μ μ΄)
미리 μ€λΉλ μλ΅μ μ 곡νμ¬ ν μ€νΈκ° μνλ νΉμ μνλ₯Ό κ°λλ‘ λ§λλ λ° μ¬μ©λλ©°, κ°μ²΄μ μν(State)μ μ΄μ μ λ§μΆ₯λλ€.
μμ:
when(stubRepository.findById(1L)).thenReturn(Optional.of(user));
μ κ°μ΄findById(1L)
μ΄ νΈμΆλλ©΄ 미리 μ€λΉλuser
κ°μ²΄λ₯Ό λ°ννλλ‘ μ€μ ν©λλ€.
Mockμ Stubμ κΈ°λ₯μ ν¬ν¨ν μ μμ΅λλ€. λμ ꡬλΆνλ ν΅μ¬ κΈ°μ€μ βκ²μ¦μ λͺ©μ βμ λλ€.
κ²μ¦νλ €λ λͺ©μ μ΄ βνΉμ λ©μλμ νΈμΆ μ¬λΆβλΌλ©΄ Mockμ, βν μ€νΈ μ€νμ μν νΉμ μνλ λ°ν κ°βμ΄ μ€μνλ€λ©΄ Stubμ μ¬μ©νλ κ²μ΄ μ’μ΅λλ€.
πΊ ν μ€νΈ νΌλΌλ―Έλ (Test Pyramid) λ° ν μ€νΈ μ’ λ₯
ν μ€νΈ νΌλΌλ―Έλλ ν¨κ³Όμ μΈ ν μ€νΈ μ λ΅μ μκ°μ μΌλ‘ λνλ΄λ λͺ¨λΈμ λλ€. νΌλΌλ―Έλμ κ° μΈ΅μ ν μ€νΈμ μ’ λ₯, λ²μ, λΉμ©, μ€ν μλ κ°μ κ΄κ³λ₯Ό 보μ¬μ€λλ€.
κ°μ₯ ν¨μ¨μ μΈ ν μ€νΈ μ λ΅μ νΌλΌλ―Έλμ μλμͺ½(λ¨μ ν μ€νΈ)μ μ§μ€νκ³ , μλ¨λΆ(E2E ν μ€νΈ)λ μ΅μννλ κ²μ λλ€.
π§ͺ Unit Testing (λ¨μ ν μ€νΈ)
- π― λμ: λ¨μΌ κΈ°λ₯, ν¨μ, ν΄λμ€μ κ°μ κ°μ₯ μμ μ½λ λΈλ‘.
- π λͺ©μ : μ½λ μ‘°κ°μ΄ λ 립μ μΌλ‘ μ ννκ² λμνλμ§ λΉ λ₯΄κ² κ²μ¦ν©λλ€.
- β¨ νΉμ§: μΈλΆ μμ€ν μμ‘΄ μμ΄ λ©λͺ¨λ¦¬ μμμ λ§€μ° λΉ λ₯΄κ² μ€νλ©λλ€. μ½λ λ³κ²½ μ κ°μ₯ λ¨Όμ , κ·Έλ¦¬κ³ κ°μ₯ μμ£Ό μ€νλμ΄ μ¦κ°μ μΈ νΌλλ°±μ μ 곡ν©λλ€.
- βοΈ μμ± μμ : λͺ¨λ κ°λ°μκ° μ½λ μμ±κ³Ό λμμ κ°μ₯ λΉλ²νκ² μμ±νλ κΈ°λ³Έ ν μ€νΈμ λλ€.
βκ°μμμλ λ€λ₯Έ κ°μ²΄λ μμ€ν μ μμ‘΄νμ§ μκ³ , μ¨μ ν μμ μ κΈ°λ₯λ§ ν μ€νΈνλ λ 립μ μΈ ν μ€νΈλΌκ³ μ μν©λλ€.β
π§© Integration Testing (ν΅ν© ν μ€νΈ)
- π― λμ: μλ‘ λ€λ₯Έ λͺ¨λ, μ»΄ν¬λνΈ, μλΉμ€ κ°μ μνΈμμ©.
- π λͺ©μ : μ¬λ¬ λͺ¨λμ΄ ν΅ν©λμμ λ μμλλ‘ νλ ₯νκ³ λμνλμ§ κ²μ¦ν©λλ€.
- β¨ νΉμ§: λ¨μ ν μ€νΈλ³΄λ€ λμ λ²μλ₯Ό λ€λ£¨λ©°, Mockμ μ¬μ©νκ±°λ μ€μ μμ€ν (e.g., In-memory DB)μ νμ©ν μ μμ΅λλ€.
- βοΈ μμ± μμ : ν΅μ¬ λΉμ¦λμ€ λ‘μ§μ΄λ μλΉμ€ κ°μ μ€μν μνΈμμ© μ§μ μ κ²μ¦ν λ μμ±ν©λλ€.
μ€λ¬΄μμλ λͺ©μ μ λ°λΌ λ μ’ λ₯λ‘ λλ μ μμ΅λλ€.
- κ°λ° λ 벨 ν΅ν© ν
μ€νΈ: μ ν리μΌμ΄μ
λ΄λΆμμ μ¬λ¬ μ»΄ν¬λνΈ(Controller-Service-Repository)κ° μ μμ μΌλ‘ μ°λλλμ§ κ²μ¦ν©λλ€. (
JUnit
+@SpringBootTest
,Testcontainers
,H2
λ±μ μ¬μ©)λ¨μ ν μ€νΈμ λ¬λ¦¬ βμ€μ Bean κ° μ°λ, DB νΈλμμ λ± μ€μ νκ²½μ κ°κΉμ΄ μν©μ κ²μ¦βνλ λ° λͺ©μ μ΄ μμ΅λλ€.
- QA/λ°°ν¬ λ¨κ³ ν΅ν© ν μ€νΈ (SIT): μ¬λ¬ μλΉμ€κ° ν΅ν©λ νκ²½(e.g., Staging)μμ μ 체 μμ€ν μ μ°λμ νμΈν©λλ€. μ£Όλ‘ QAνμ΄ μλλ¦¬μ€ κΈ°λ°μΌλ‘ ν μ€νΈλ₯Ό μνν©λλ€.
π₯οΈ End-to-End Testing (E2E ν μ€νΈ)
- π― λμ: μ€μ μ¬μ©μμ μλ리μ€μ λμΌν μ 체 μ ν리μΌμ΄μ μ νλ¦.
- π λͺ©μ : μ΅μ’ μ¬μ©μ κ΄μ μμ μμ€ν μ μ²΄κ° μ²μλΆν° λκΉμ§ μ μ μλνλμ§ κ²μ¦ν©λλ€.
- β¨ νΉμ§: μ€μ μ λμΌν νκ²½μμ μνλλ―λ‘ μ λ’°λκ° λμ§λ§, μμ± λΉμ©μ΄ ν¬κ³ μ€ν μκ°μ΄ λ§€μ° κΉλλ€. λ°λΌμ ν΅μ¬ μλ리μ€μ λν΄μλ§ μ΅μνμΌλ‘ μμ±ν΄μΌ ν©λλ€.
- βοΈ μμ± μμ : λ°°ν¬ μ§μ , μμ€ν
μ μ΅μ’
μ μΈ μμ μ±μ 보μ₯νκΈ° μν΄ μ€νν©λλ€. (
Cypress
,Playwright
,Selenium
,RestAssured
λ±μ λꡬλ₯Ό μ¬μ©)
π Testable Code μμ±λ²κ³Ό μ£Όμμ¬ν
- λͺ¨λ νλ‘λμ μ½λλ ν μ€νΈ κ°λ₯νκ²(Testable) ꡬννλ κ²μ λͺ©νλ‘ μΌμ΅λλ€.
- ν μ€νΈ 컀λ²λ¦¬μ§ 100%μ μ§μ°©ν기보λ€, μλ―Έ μκ³ μ λ’°μ± λμ ν μ€νΈλ₯Ό μμ±νλ λ° μ§μ€ν©λλ€.
- ν
μ€νΈ μμ±μ μ΄λ ΅κ² λ§λλ μ½λ(e.g.,
private
λ©μλ, κ°ν κ²°ν©)λ 리ν©ν λ§μ ν΅ν΄ κ°μ ν©λλ€. - ν μ€νΈμ μ±κ³΅μ΄ κ³§ κΈ°λ₯ ꡬνμ μλ£λ₯Ό μλ―Ένλλ‘ κ°λ° νλ‘μΈμ€λ₯Ό μ 립ν©λλ€.
π οΈ μ€λ¬΄ ν μ€νΈ μ½λ μμ± μ κ³ λ €μ¬ν λ° κ·μΉ
μ€λ¬΄μμλ λ¨μ ν μ€νΈλ₯Ό κΈ°λ³ΈμΌλ‘ μΌλ κ²μ΄ κ°μ₯ μμ μ μ΄κ³ ν¨μ¨μ μ λλ€. λ¨μ ν μ€νΈλ μΈλΆ μμΈμΌλ‘λΆν° κ°λ°μλ₯Ό 보νΈνλ κ°μ₯ κ°λ ₯ν λ°©μ΄ μλ¨μ λλ€.
β μ§μΌμΌ ν ν μ€νΈ μ½λ κ·μΉ
- ν ν μ€νΈλ ν κ°μ§ μ± μλ§ κ²μ¦: κ° ν μ€νΈλ λͺ νν λ¨μΌ λͺ©μ μ κ°μ ΈμΌ ν©λλ€.
- μΈλΆ μμ‘΄μ± μ μ΄: μ€μ DBλ μΈλΆ API λμ Mock κ°μ²΄λ₯Ό μ¬μ©νμ¬ ν μ€νΈμ λ 립μ±κ³Ό μλλ₯Ό ν보ν©λλ€.
- ν
μ€νΈ μ¬νμ± ν보: μ€νν λλ§λ€ κ²°κ³Όκ° λ¬λΌμ§λ λλ€ κ°μ΄λ νμ¬ μκ°(e.g.,
LocalDateTime.now()
)μ μμ‘΄νλ μ½λλ₯Ό μ κ±°νμ¬ μΌκ΄λ κ²°κ³Όλ₯Ό 보μ₯ν©λλ€. - λͺ νν ν μ€νΈ μ΄λ¦ (Given-When-Then): ν μ€νΈμ 쑰건(Given), μ€ν(When), κΈ°λ κ²°κ³Ό(Then)κ° λλ¬λλλ‘ μ΄λ¦μ μ§μ΄, μ΄λ¦λ§ λ΄λ ν μ€νΈμ μλλ₯Ό νμ ν μ μκ² ν©λλ€.
- λͺ
νν Assertion:
isTrue()
,isNotNull()
κ³Ό κ°μ λͺ¨νΈν κ²μ¦ λμ , κΈ°λνλ κ°μ΄λ μνλ₯Ό λͺ νν λͺ μν©λλ€. (e.g.,isEqualTo(expectedValue)
)
β νΌν΄μΌ ν μν°ν¨ν΄
- ν
μ€νΈ κ° μν 곡μ : ν
μ€νΈλ μλ‘ λ
립μ μ΄μ΄μΌ ν©λλ€.
@BeforeEach
λ±μ νμ©νμ¬ λ§€λ² κΉ¨λν μνμμ μμνλλ‘ ν©λλ€. Thread.sleep()
μ¬μ©: ν μ€νΈλ₯Ό λλ¦¬κ³ λΆμμ νκ² λ§λλλ€. λΉλκΈ° μ½λλ₯Ό ν μ€νΈν λλAwaitility
μ κ°μ μ λ¬Έ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©ν©λλ€.- μλ―Έ μλ ν
μ€νΈ μ΄λ¦:
test1()
,doTest()
μ κ°μ΄ λͺ©μ μ μ μ μλ μ΄λ¦μ μ§μν©λλ€. - κ³Όλν Mock κ²μ¦: λ΄λΆ ꡬνμ λ무 κΉμ΄ κ΄μ¬νλ ν μ€νΈλ 리ν©ν λ§μ λ°©ν΄ν©λλ€.
βμ΄ λ©μλκ° λͺ λ² νΈμΆλμλβμ κ°μ λ΄λΆ ꡬν λ°©μμ μ§μ°©ν기보λ€, βκ·Έλμ μ΅μ’ μ μΌλ‘ μΈλΆλ‘ 보μ΄λ κ²°κ³Όκ° λ¬΄μμΈκ°β λΌλ νμ(Behavior) μ€μ¬μ κ²μ¦μ μ§μ€νλ κ²μ΄ λ κ²¬κ³ ν ν μ€νΈλ₯Ό λ§λλλ€.