관리 메뉴

deVlog

[TDD] ν…ŒμŠ€νŠΈ 더블 - Mock vs Stub vs Spy λ³Έλ¬Έ

πŸ”– Test Driven Development

[TDD] ν…ŒμŠ€νŠΈ 더블 - Mock vs Stub vs Spy

은루밍 2024. 8. 31. 13:06

λͺ©μ°¨

     

     

    πŸ§‘‍🀝‍πŸ§‘ ν…ŒμŠ€νŠΈ 더블

    https://martinfowler.com/bliki/TestDouble.html

    ν…ŒμŠ€νŠΈ 더블은 μ†Œν”„νŠΈμ›¨μ–΄ ν…ŒμŠ€νŠΈμ—μ„œ μ‹€μ œ 객체λ₯Ό λŒ€μ‹ ν•˜μ—¬ μ‚¬μš©λ˜λŠ” κ°€μ§œ 객체 λ“€λ‘œ, ν…ŒμŠ€νŠΈ ν™˜κ²½μ—μ„œ λ‹€μ–‘ν•œ λͺ©μ μ„ μœ„ν•΄ ν™œμš©λœλ‹€.

    λ§ˆν‹΄ νŒŒμšΈλŸ¬λŠ” μœ„μ˜ κ²Œμ‹œκΈ€μ—μ„œ ν…ŒμŠ€νŠΈ 더블을 λ‹€μ„― κ°€μ§€λ‘œ λΆ„λ₯˜ν–ˆλ‹€.

    • Dummy : κ°μ²΄λŠ” μ „λ‹¬λ˜μ§€λ§Œ μ‹€μ œλ‘œ μ‚¬μš©λ˜μ§€ μ•ŠλŠ”λ‹€. 일반적으둜 νŒŒλΌλ―Έν„°λ₯Ό μ „λ‹¬ν•˜κΈ° μœ„ν•œ μš©λ„λ‘œλ§Œ μ‚¬μš©λœλ‹€.
    • Fake : μ‹€μ œλ‘œ λ™μž‘ν•˜λŠ” 객체λ₯Ό μ˜λ―Έν•œλ‹€. 보톡 ν”„λ‘œλ•μ…˜μ— ν™˜κ²½μ— μ ν•©ν•˜μ§€ μ•Šμ€ 지름길 역할을 ν•œλ‹€. (인메λͺ¨λ¦¬ λ°μ΄ν„°λ² μ΄μŠ€ κ°€ 쒋은 μ˜ˆμ‹œμ΄λ‹€).
    • Stub : ν…ŒμŠ€νŠΈ 쀑에 호좜된 κ²½μš°μ— λŒ€ν•΄ 미리 μ •ν•΄μ§„ 값을 μ‘λ‹΅ν•œλ‹€. 보톡 ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•΄ λ§Œλ“€μ–΄μ§€λ©° ν…ŒμŠ€νŠΈ 이외에 μ‚¬μš©λ˜μ§€ μ•ŠλŠ”λ‹€.
    • Spy : 호좜 방식에 따라 일뢀 정보λ₯Ό κΈ°λ‘ν•˜λŠ” μŠ€ν…μ΄λΌ ν•  수 μžˆλ‹€. 주둜 μ–΄λ–€ λ™μž‘μ΄ μ΄λ£¨μ–΄μ‘ŒλŠ”μ§€ κ²€μ¦ν•˜λŠ” μš©λ„λ‘œ μ‚¬μš©ν•œλ‹€. μ „μ†‘λœ λ©”μ‹œμ§€ 수λ₯Ό κΈ°λ‘ν•˜λŠ” 이메일 μ„œλΉ„μŠ€κ°€ ν•œ μ˜ˆμ‹œμ΄λ‹€.
    • Mock : ν˜ΈμΆœν–ˆμ„ λ•Œ 사전에 μ •μ˜λœ λͺ…μ„ΈλŒ€λ‘œμ˜ κ²°κ³Όλ₯Ό λŒλ €μ£Όλ„λ‘ 미리 ν”„λ‘œκ·Έλž˜λ°λ˜μ–΄ μžˆλ‹€. μ˜ˆμƒμΉ˜ λͺ»ν•œ 호좜이 μžˆμ„ 경우 μ˜ˆμ™Έλ₯Ό 던질 수 있으며, λͺ¨λ“  호좜이 μ˜ˆμƒλœ κ²ƒμ΄μ—ˆλŠ”μ§€ 확인할 수 μžˆλ‹€.

    μœ„μ— μ •μ˜λœ ν…ŒμŠ€νŠΈ 더블 μ€‘μ—μ„œ Mock 만 ν–‰μœ„λ₯Ό κ²€μ¦ν•œλ‹€. 보톡 λ‹€λ₯Έ 더블은 μƒνƒœ 검증을 μœ„ν•΄ μ‚¬μš©ν•œλ‹€.

     

    πŸ”Ž μƒνƒœ 검증 vs ν–‰μœ„ 검증

    μƒνƒœ 검증과 ν–‰μœ„ 검증은 μ†Œν”„νŠΈμ›¨μ–΄ ν…ŒμŠ€νŠΈμ—μ„œ μ‚¬μš©λ˜λŠ” 두 κ°€μ§€ μ£Όμš” μ ‘κ·Ό 방식이며, ν…ŒμŠ€νŠΈ λŒ€μƒμ˜ λ™μž‘μ„ κ²€μ¦ν•˜λŠ” 방법에 차이λ₯Ό 두고 μžˆλ‹€.

     

    μƒνƒœ 검증 (State Verification)

    • μ‹œμŠ€ν…œμ΄ νŠΉμ • μƒνƒœμ— λ„λ‹¬ν–ˆλŠ”μ§€λ₯Ό ν™•μΈν•˜λŠ” ν…ŒμŠ€νŠΈ 방식이닀.
    • 주둜 μ‹œμŠ€ν…œμ˜ λ©”μ„œλ“œλ‚˜ κΈ°λŠ₯이 호좜된 후에, κ·Έ 결과둜 μ‹œμŠ€ν…œμ˜ μƒνƒœκ°€ μ˜ˆμƒλœ λŒ€λ‘œ λ³€ν–ˆλŠ”μ§€λ₯Ό κ²€μ‚¬ν•œλ‹€.

    μ˜ˆμ‹œ) 은행 κ³„μ’Œμ— λˆμ„ μž…κΈˆν•˜λŠ” λ©”μ„œλ“œλ₯Ό ν…ŒμŠ€νŠΈν•  λ•Œ, μž…κΈˆ ν›„ κ³„μ’Œ μž”κ³ κ°€ μ˜¬λ°”λ₯΄κ²Œ μ—…λ°μ΄νŠΈλ˜μ—ˆλŠ”μ§€λ₯Ό ν™•μΈν•œλ‹€.

    • 상황 : 은행 κ³„μ’Œμ— λˆμ„ μž…κΈˆν•˜λŠ” κΈ°λŠ₯을 ν…ŒμŠ€νŠΈ
    • ν…ŒμŠ€νŠΈ : κ³„μ’Œμ— 100,000원을 μž…κΈˆν•œ ν›„, μž”κ³ κ°€ 500,000μ›μ—μ„œ 600,000μ›μœΌλ‘œ μ¦κ°€ν–ˆλŠ”μ§€λ₯Ό ν™•μΈν•œλ‹€.
    • 검증 : μž…κΈˆ ν›„ κ³„μ’Œ μž”κ³ κ°€ 600,000원이 λ˜μ—ˆλŠ”μ§€λ₯Ό ν™•μΈν•˜μ—¬ μƒνƒœλ₯Ό κ²€μ¦ν•œλ‹€.

    ν–‰μœ„ 검증 (Behavior Verification)

    • μ‹œμŠ€ν…œμ΄ μ˜¬λ°”λ₯Έ μ ˆμ°¨λ‚˜ 방법을 따라 μž‘λ™ν–ˆλŠ”μ§€λ₯Ό ν™•μΈν•˜λŠ” ν…ŒμŠ€νŠΈ 방식이닀.
    • νŠΉμ • μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” λ™μ•ˆ μ˜¬λ°”λ₯Έ λ©”μ„œλ“œλ‚˜ 절차λ₯Ό ν˜ΈμΆœν–ˆλŠ”μ§€, νŠΉμ • μΈν„°νŽ˜μ΄μŠ€μ™€ μ˜¬λ°”λ₯΄κ²Œ μƒν˜Έμž‘μš© ν–ˆλŠ”μ§€λ₯Ό κ²€μ‚¬ν•œλ‹€.

    μ˜ˆμ‹œ) 은행 κ³„μ’Œμ— λˆμ„ μž…κΈˆν•˜λŠ” λ©”μ„œλ“œλ₯Ό ν…ŒμŠ€νŠΈν•  λ•Œ, μž…κΈˆ κ³Όμ •μ—μ„œ μ˜¬λ°”λ₯Έ λ©”μ„œλ“œλ“€μ΄ ν˜ΈμΆœλ˜μ—ˆλŠ”μ§€λ₯Ό ν™•μΈν•œλ‹€.

    • 상황: 은행 κ³„μ’Œμ— λˆμ„ μž…κΈˆν•˜λŠ” κΈ°λŠ₯을 ν…ŒμŠ€νŠΈ
    • ν…ŒμŠ€νŠΈ: κ³„μ’Œμ— 100,000원을 μž…κΈˆν•˜λŠ” λ™μ•ˆ, μž”κ³  μ—…λ°μ΄νŠΈ λ©”μ„œλ“œμ™€ μž…κΈˆ λ‚΄μ—­ 기둝 λ©”μ„œλ“œκ°€ μ˜¬λ°”λ₯Έ μˆœμ„œλ‘œ ν˜ΈμΆœλ˜μ—ˆλŠ”μ§€λ₯Ό ν™•μΈν•œλ‹€.
    • 검증: μž…κΈˆ κ³Όμ •μ—μ„œ μž”κ³  μ—…λ°μ΄νŠΈ λ©”μ„œλ“œκ°€ ν˜ΈμΆœλ˜μ—ˆκ³ , κ·Έ ν›„ μž…κΈˆ λ‚΄μ—­ 기둝 λ©”μ„œλ“œκ°€ ν˜ΈμΆœλ˜μ—ˆλŠ”μ§€λ₯Ό ν™•μΈν•˜μ—¬ ν–‰μœ„λ₯Ό κ²€μ¦ν•œλ‹€.
    μƒνƒœ 검증은 μ‹œμŠ€ν…œμ˜ κ²°κ³Όλ₯Ό μ€‘μ μ μœΌλ‘œ ν™•μΈν•˜λ©°, μ΅œμ’… μƒνƒœκ°€ μ˜¬λ°”λ₯Έμ§€μ— μ΄ˆμ μ„ λ§žμΆ˜λ‹€.
    ν–‰μœ„ 검증은 μ‹œμŠ€ν…œμ˜ 행동 과정을 μ€‘μ μ μœΌλ‘œ ν™•μΈν•˜λ©°, μ‹œμŠ€ν…œμ΄ μ˜¬λ°”λ₯΄κ²Œ ν–‰λ™ν–ˆλŠ”μ§€λ₯Ό ν‰κ°€ν•œλ‹€.

    두 검증 방식은 μ„œλ‘œ 보완적이며, νŠΉμ • 상황에 따라 ν•˜λ‚˜ λ˜λŠ” λ‘˜ λ‹€ μ‚¬μš©ν•  수 μžˆλ‹€.

     

     

     πŸ₯Έ Mock : κΈ°λŒ€ν•œ λŒ€λ‘œ 잘 호좜이 λ˜λ‚˜? - ν–‰μœ„ 검증

    Mock 은 νŠΉμ • λ©”μ„œλ“œ 호좜이 μ˜ˆμƒλŒ€λ‘œ μ΄λ£¨μ–΄μ‘ŒλŠ”μ§€ ν™•μΈν•˜κΈ° μœ„ν•œ λͺ©μ μœΌλ‘œ μ‚¬μš©λœλ‹€.

    Mock의 νŠΉμ§•

    • ν˜ΈμΆœμ— λŒ€ν•œ κΈ°λŒ€λ₯Ό λͺ…μ„Έν•˜κ³ , λ‚΄μš©μ— 따라 λ™μž‘ν•˜λ„λ‘ ν”„λ‘œκ·Έλž˜λ°λœ 객체이닀.
    • ν–‰μœ„ 검증을 μˆ˜ν–‰ν•œλ‹€.
    • λ°˜ν™˜κ°’μ΄ μ—†λŠ” ν•¨μˆ˜λ‚˜, νŠΉμ • ν•¨μˆ˜ 호좜 μ—¬λΆ€λ₯Ό ν…ŒμŠ€νŠΈν•  λ•Œ 주둜 μ‚¬μš©λœλ‹€.
    • @Mock μ–΄λ…Έν…Œμ΄μ…˜μ„ 톡해 μƒμ„±λ˜λ©°, stubbing을 톡해 λ°˜ν™˜κ°’μ„ μ„€μ •ν•  수 μžˆλ‹€. stubbing을 ν•˜μ§€ μ•ŠμœΌλ©΄ κΈ°λ³Έ κ°’(μ°Έμ‘°ν˜•μ€ null, κΈ°λ³Έν˜•μ€ 0)을 λ°˜ν™˜ν•œλ‹€.

    Mock 은 ν…ŒμŠ€νŠΈ 쀑에 νŠΉμ • μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” 객체λ₯Ό λŒ€μ²΄ν•˜λŠ” 데 μ‚¬μš©λœλ‹€. 즉, κ°€μ§œ ν…ŒμŠ€νŠΈ μˆ˜λ‹¨μ„ λ§Œλ“€μ–΄ λ‘λŠ” 것이닀.

    μ΄λ ‡κ²Œ λŒ€μ²΄λœ Mock κ°μ²΄λŠ” μœ„μ— μ–ΈκΈ‰ν•œ λŒ€λ‘œ νŠΉμ • λ©”μ„œλ“œκ°€ ν˜ΈμΆœλ˜μ—ˆλŠ”μ§€, μ–΄λ–€ 인자둜 ν˜ΈμΆœλ˜μ—ˆλŠ”μ§€ κ²€μ‚¬ν•˜λŠ” 데 쀑점을 λ‘”λ‹€.

     

     

    πŸ“š Stub : κΈ°λŒ€ν•œ 값이 잘 λ°˜ν™˜λ˜λ‚˜? - μƒνƒœ 검증

    Stub κ°μ²΄λŠ” νŠΉμ • ν•¨μˆ˜ 호좜 μ‹œ μ˜ˆμƒλœ 값을 λ°˜ν™˜ν•˜λ„λ‘ μ„€μ •λœ 객체이닀.

    Stub의 νŠΉμ§•

    • μΈμŠ€ν„΄μŠ€ν™”ν•˜μ—¬ κ΅¬ν˜„ν•œ κ°€μ§œ 객체(Dummy, κΈ°λŠ₯ κ΅¬ν˜„μ΄ μ—†μŒ)λ₯Ό μ΄μš©ν•΄ μ‹€μ œλ‘œ λ™μž‘ν•˜λŠ” κ²ƒμ²˜λŸΌ 보이게 λ§Œλ“œλŠ” 객체이닀.
    • μΈν„°νŽ˜μ΄μŠ€ λ˜λŠ” κΈ°λ³Έ 클래슀λ₯Ό μ΅œμ†Œν•œμœΌλ‘œ κ΅¬ν˜„ν•œλ‹€.
    • μƒνƒœ 검증을 μœ„ν•΄ μ‚¬μš©λœλ‹€. 즉, ν•¨μˆ˜ 호좜 ν›„ 객체의 μƒνƒœκ°€ μ˜¬λ°”λ₯Έμ§€ ν™•μΈν•œλ‹€.
    • ν…ŒμŠ€νŠΈ μ‹œμ— ν”„λ‘œκ·Έλž˜λ°λœ 것 μ™Έμ—λŠ” μ‘λ‹΅ν•˜μ§€ μ•ŠλŠ”λ‹€.
    • ν˜‘λ ₯ 객체의 νŠΉμ • 뢀뢄이 ν…ŒμŠ€νŠΈκ°€ μ–΄λ €μš΄ 경우, stub을 μ‚¬μš©ν•˜μ—¬ μˆ˜μ›”ν•˜κ²Œ ν…ŒμŠ€νŠΈν•  수 μžˆλ‹€.
    • ν…ŒμŠ€νŠΈ 쀑에 μ‚¬μš©λ˜λŠ” ν•˜λ“œμ½”λ”© 된 κ°’ λ˜λŠ” 응닡을 μ œκ³΅ν•˜λŠ” 데 μ‚¬μš©λœλ‹€.

    Stub은 νŠΉμ • κ°μ²΄μ—μ„œ νŠΉμ • ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  λ•Œ, νŠΉμ •ν•œ 값이 λ°˜ν™˜λ˜κΈ°λ₯Ό κΈ°λŒ€ν•˜λ©° 더미 데이터λ₯Ό μ§€μ •ν•  λ•Œ μ‚¬μš©ν•œλ‹€.

    λ³΅μž‘ν•œ λ‘œμ§μ΄λ‚˜ μ™ΈλΆ€ μ‹œμŠ€ν…œκ³Όμ˜ μƒν˜Έμž‘μš©μ„ λ‹¨μˆœν™”ν•˜κ³ , ν…ŒμŠ€νŠΈλ₯Ό 더 예츑 κ°€λŠ₯ν•˜κ²Œ λ§Œλ“œλŠ” 데 쀑점을 λ‘”λ‹€.

     

     

    πŸ‘€ Spy : μ˜ˆμƒν•œ λ™μž‘κ³Ό μƒνƒœλ₯Ό κ°μ‹œ

    SpyλŠ” νŠΉμ • ν•¨μˆ˜λ§Œ μ‹€μ œ ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κ²Œ ν•˜κ³  싢을 λ•Œ, 기쑴의 κ°μ²΄λ‚˜ ν•¨μˆ˜λ₯Ό κ°μ‹œν•˜λŠ” 데에 μ‚¬μš©λœλ‹€. μ΄λ•Œ ν•¨μˆ˜ 호좜, μ „λ‹¬λœ 인자, λ°˜ν™˜ κ°’ 등을 κΈ°λ‘ν•˜μ§€λ§Œ, μ‹€μ œ 둜직의 λ™μž‘μ„ λ³€κ²½ν•˜μ§€λŠ” μ•ŠλŠ”λ‹€.

    Spy의 νŠΉμ§•

    • νŠΉμ • ν•¨μˆ˜μ˜ 호좜 횟수, μ „λ‹¬λœ 인자, λ°˜ν™˜ κ°’ 등을 κΈ°λ‘ν•œλ‹€.
    • μ‹€μ œ 객체의 λ™μž‘μ„ μœ μ§€ν•˜λ©΄μ„œ νŠΉμ • λΆ€λΆ„λ§Œ κ°μ‹œν•˜κ±°λ‚˜ μ‘°μž‘ν•˜κ³  싢을 λ•Œ μ‚¬μš©ν•œλ‹€.
      뢀뢄적인 μŠ€ν„°λΉ™μ„ 톡해 μœ μ—°ν•˜κ²Œ ν…ŒμŠ€νŠΈλ₯Ό μ§„ν–‰ν•  수 μžˆλ‹€.
    • @Spy μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λ©°, stubbing을 ν•˜μ§€ μ•ŠμœΌλ©΄ μ‹€μ œ 둜직이 μˆ˜ν–‰λœλ‹€. stubbing 을 ν•˜λ©΄ μ„€μ •λœ 값을 λ°˜ν™˜ν•œλ‹€.

     

    β“μ–΄λŠ 상황에 μ–΄λ– ν•œ ν…ŒμŠ€νŠΈ 더블을 μ‚¬μš©ν•΄μ•Ό ν• κΉŒ

    Mock을 μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” 경우

    1. 전체 객체λ₯Ό κ°€μ§œλ‘œ λŒ€μ²΄ν•˜κ³  싢을 λ•Œ
      ν…ŒμŠ€νŠΈ ν™˜κ²½μ—μ„œ λ³΅μž‘ν•œ μ˜μ‘΄μ„±μ„ μ œκ±°ν•˜κ³ , ν…ŒμŠ€νŠΈν•˜κ³ μž ν•˜λŠ” λΆ€λΆ„μ—λ§Œ μ§‘μ€‘ν•œλ‹€. 예λ₯Ό λ“€μ–΄, μ™ΈλΆ€ API ν˜ΈμΆœμ„ μ™„μ „νžˆ Mockingν•˜μ—¬ ν…ŒμŠ€νŠΈν•  λ•Œ μ‚¬μš©ν•œλ‹€.
    2. ν–‰μœ„ 검증(Behavior Verification)에 μ§‘μ€‘ν•˜κ³  싢을 λ•Œ
      νŠΉμ • λ©”μ„œλ“œκ°€ ν˜ΈμΆœλ˜μ—ˆλŠ”μ§€, 호좜된 횟수, 호좜된 인자 등을 검증할 λ•Œ Mock을 μ‚¬μš©ν•œλ‹€.
      μ΄λ•Œ Mock은 μ‹€μ œ λ™μž‘μ„ μˆ˜ν–‰ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ, μ™ΈλΆ€ μ‹œμŠ€ν…œκ³Όμ˜ μƒν˜Έμž‘μš©μ„ ν…ŒμŠ€νŠΈν•  λ•Œ μ•ˆμ „ν•˜κ²Œ μ‚¬μš©ν•  수 μžˆλ‹€.
    3. ν…ŒμŠ€νŠΈκ°€ μ‹€μ œ λ™μž‘κ³Ό 무관할 λ•Œ
      ν…ŒμŠ€νŠΈκ°€ νŠΉμ • 둜직의 μ‹€ν–‰ μ—¬λΆ€λ‚˜ λ°©μ‹μ—λ§Œ 관심이 있고, κ·Έ 둜직의 μ‹€μ œ κ²°κ³Όλ‚˜ μƒνƒœλŠ” μ€‘μš”ν•˜μ§€ μ•Šμ„ λ•Œ μ‚¬μš©ν•œλ‹€.
      예λ₯Ό λ“€μ–΄, 이벀트 ν•Έλ“€λŸ¬κ°€ μ˜¬λ°”λ₯΄κ²Œ λ“±λ‘λ˜κ³  ν˜ΈμΆœλ˜λŠ”μ§€ ν™•μΈν•˜κ³ , κ·Έ κ²°κ³ΌλŠ” μ€‘μš”ν•˜μ§€ μ•Šμ€ κ²½μš°μ— μ ν•©ν•˜λ‹€.

    Stub을 μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” 경우

    1. ν…ŒμŠ€νŠΈμ˜ μž…λ ₯에 집쀑할 λ•Œ
      μž…λ ₯ 값에 따라 λ¦¬ν„΄ν•˜λŠ” 결괏 값을 λΉ„κ΅ν•˜κ±°λ‚˜, νŠΉμ • μž…λ ₯ 값에 λŒ€ν•œ μ˜ˆμ™Έ λ°œμƒ μ—¬λΆ€λ₯Ό ν™•μΈν•œλ‹€. 예λ₯Ό λ“€μ–΄, λ©”μ„œλ“œκ°€ μ£Όμ–΄μ§„ μž…λ ₯에 λŒ€ν•΄ μ˜ˆμƒλœ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•˜λŠ”μ§€ 검증할 λ•Œ μ‚¬μš©ν•œλ‹€.
    2. μž…λ ₯에 따라 μ˜ˆμ™Έκ°€ λ°œμƒν•˜λŠ”μ§€ 확인할 λ•Œ
      νŠΉμ • μž…λ ₯ 값이 μ£Όμ–΄μ‘Œμ„ λ•Œ, λ©”μ„œλ“œκ°€ μ˜¬λ°”λ₯΄κ²Œ μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚€λŠ”μ§€ ν™•μΈν•œλ‹€. 예λ₯Ό λ“€μ–΄, 잘λͺ»λœ μž…λ ₯에 λŒ€ν•œ μ μ ˆν•œ μ˜ˆμ™Έ 처리λ₯Ό ν…ŒμŠ€νŠΈν•  λ•Œ μ‚¬μš©ν•œλ‹€.

    Spyλ₯Ό μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” 경우

    1. λΆ€λΆ„μ μœΌλ‘œ μ‹€μ œ 객체의 λ™μž‘μ„ μœ μ§€ν•˜κ³  싢을 λ•Œ
      μ‹€μ œ 객체λ₯Ό μƒμ„±ν•œ ν›„, 일뢀 λ©”μ„œλ“œλ§Œ κ°μ‹œν•˜κ±°λ‚˜ μŠ€ν„°λΉ™(stubbing) ν•  수 μžˆλ‹€. λ³΅μž‘ν•œ ν΄λž˜μŠ€μ—μ„œ νŠΉμ • λ©”μ„œλ“œμ˜ 호좜 νšŸμˆ˜λ‚˜ 인자λ₯Ό ν™•μΈν•˜λ©΄μ„œλ„ λ‚˜λ¨Έμ§€ λ©”μ„œλ“œλ“€μ€ μ›λž˜μ˜ λ™μž‘μ„ μœ μ§€ν•˜κ³  싢을 λ•Œ μ‚¬μš©ν•œλ‹€.
    2. μ‹€μ œ λ‘œμ§μ„ ν…ŒμŠ€νŠΈν•˜λ©΄μ„œ νŠΉμ • λΆ€λΆ„λ§Œ μ‘°μž‘ν•˜κ³  싢을 λ•Œ
      전체 λ©”μ„œλ“œ 호좜 흐름은 μœ μ§€ν•˜λ©΄μ„œ νŠΉμ • λ©”μ„œλ“œμ˜ λ°˜ν™˜κ°’λ§Œ λ³€κ²½ν•΄ ν…ŒμŠ€νŠΈλ₯Ό μ§„ν–‰ν•œλ‹€. λ³΅μž‘ν•œ 계산을 μˆ˜ν–‰ν•˜λŠ” λ©”μ„œλ“œμ˜ 일뢀 결과만 μ‘°μž‘ν•˜κ³ , λ‚˜λ¨Έμ§€ 흐름은 κ·ΈλŒ€λ‘œ μœ μ§€ν•˜κ³  싢을 λ•Œ μœ μš©ν•˜λ‹€.

     

     

    spy μ‚¬μš© μ˜ˆμ‹œ μ½”λ“œ

    더보기
    public class Calculator {
        public int add(int a, int b) {
            return a + b;
        }
        public int multiply(int a, int b) {
            return a * b;
        }
        public int subtract(int a, int b) {
            return a - b;
        } 
    }



    public class SpyCalculator extends Calculator {
        private final List<String> methodCalls = new ArrayList<>();
    
        @Override
        public int add(int a, int b) {
            methodCalls.add("add(" + a + ", " + b + ")");
            return super.add(a, b);  // μ‹€μ œ λ©”μ„œλ“œ 호좜
        }
    
        @Override
        public int multiply(int a, int b) {
            methodCalls.add("multiply(" + a + ", " + b + ")");
            return 100;  // μŠ€ν„°λΉ™ 처리된 κ°’
        }
        
        // subtract 은 κ°μ‹œX, μŠ€ν„°λΉ™X
    
        // λ©”μ„œλ“œ 호좜 내역을 ν™•μΈν•˜λŠ” λ©”μ„œλ“œ
        public boolean wasMethodCalled(String methodCall) {
            return methodCalls.contains(methodCall);
        }
    }
    •  SpyCalculator ν΄λž˜μŠ€λŠ” Calculator 클래슀λ₯Ό ν™•μž₯ν•œ κ²ƒμœΌλ‘œ, λ©”μ„œλ“œ ν˜ΈμΆœμ„ κ°μ‹œν•˜κ³  νŠΉμ • λ©”μ„œλ“œμ— λŒ€ν•΄ μŠ€ν„°λΉ™μ„ μ μš©ν•œλ‹€.
    • add λ©”μ„œλ“œλŠ” μ‹€μ œ 계산을 μˆ˜ν–‰ν•˜κ³ , 호좜 내역을 κΈ°λ‘ν•œλ‹€.
    • multiply λ©”μ„œλ“œλŠ” 호좜 내역을 κΈ°λ‘ν•œ ν›„, 항상 100을 λ°˜ν™˜ν•˜λŠ” μŠ€ν„°λΉ™ 처리된 λ©”μ„œλ“œμ΄λ‹€.
    • add와 multiply λ©”μ„œλ“œκ°€ 호좜될 λ•Œ 호좜 내역을 methodCalls λ¦¬μŠ€νŠΈμ— κΈ°λ‘ν•œλ‹€. -> wasMethodCalled(String methodCall) λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ νŠΉμ • λ©”μ„œλ“œ 호좜 내역이 κΈ°λ‘λ˜μ—ˆλŠ”μ§€ 확인할 수 μžˆλ‹€.
    public class SpyCalculatorTest {
    
        @Test
        public void testOriginalCalculator() {
            // μ›λž˜μ˜ Calculator 객체 생성
            Calculator calculator = new Calculator();
    
            // μ›λž˜ Calculator의 add λ©”μ„œλ“œλŠ” μ›λž˜ λ™μž‘μ„ μˆ˜ν–‰
            int originalAddResult = calculator.add(2, 3);
            assertEquals(5, originalAddResult);
    
            // μ›λž˜ Calculator의 multiply λ©”μ„œλ“œλ„ μ›λž˜ λ™μž‘μ„ μˆ˜ν–‰
            int originalMultiplyResult = calculator.multiply(2, 3);
            assertEquals(6, originalMultiplyResult);
        }
    
        @Test
        public void testSpyCalculatorWithStubbingAndVerification() {
            // SpyCalculator 객체 생성
            SpyCalculator spyCalculator = new SpyCalculator();
    
            // multiply λ©”μ„œλ“œλŠ” μŠ€ν„°λΉ™λœ κ°’(100)을 λ°˜ν™˜
            int multiplyResult = spyCalculator.multiply(2, 3);
            assertEquals(100, multiplyResult);
    
            // add λ©”μ„œλ“œλŠ” μ‹€μ œ λ™μž‘μ„ μˆ˜ν–‰
            int addResult = spyCalculator.add(2, 3);
            assertEquals(5, addResult);
    
            // subtract λ©”μ„œλ“œλŠ” μ‹€μ œ λ™μž‘μ„ μˆ˜ν–‰
            int subtractResult = spyCalculator.subtract(5, 3);
            assertEquals(2, subtractResult);
    
            // λ©”μ„œλ“œ 호좜 κ°μ‹œ
            assertTrue(spyCalculator.wasMethodCalled("multiply(2, 3)"));  // multiply λ©”μ„œλ“œκ°€ ν˜ΈμΆœλ˜μ—ˆλŠ”μ§€ 확인
            assertTrue(spyCalculator.wasMethodCalled("add(2, 3)"));       // add λ©”μ„œλ“œκ°€ ν˜ΈμΆœλ˜μ—ˆλŠ”μ§€ 확인
        }
        
        // Mockito μ‚¬μš©
        @Test
        public void testCalculatorWithSpy() {
            // μ‹€μ œ Calculator 객체 생성
            Calculator realCalculator = new Calculator();
            // Calculator의 spy 객체 생성
            Calculator spyCalculator = spy(realCalculator);
    
            // multiply λ©”μ„œλ“œλ₯Ό μŠ€ν„°λΉ™ μ²˜λ¦¬ν•˜μ—¬ 항상 100을 λ°˜ν™˜ν•˜λ„λ‘ μ„€μ •
            doReturn(100).when(spyCalculator).multiply(2, 3);
    
            // ν…ŒμŠ€νŠΈ: multiply λ©”μ„œλ“œλŠ” μŠ€ν„°λΉ™λœ κ°’(100)을 λ°˜ν™˜
            int multiplyResult = spyCalculator.multiply(2, 3);
            assertEquals(100, multiplyResult);
    
            // ν…ŒμŠ€νŠΈ: add λ©”μ„œλ“œλŠ” μ‹€μ œ λ™μž‘μ„ μˆ˜ν–‰
            int addResult = spyCalculator.add(2, 3);
            assertEquals(5, addResult);
    
            // ν…ŒμŠ€νŠΈ: subtract λ©”μ„œλ“œλŠ” μ‹€μ œ λ™μž‘μ„ μˆ˜ν–‰
            int subtractResult = spyCalculator.subtract(5, 3);
            assertEquals(2, subtractResult);
    
            // λ©”μ„œλ“œ 호좜 검증
            verify(spyCalculator).multiply(2, 3); // multiply(2, 3) 호좜 검증
            verify(spyCalculator).add(2, 3);      // add(2, 3) 호좜 검증
            verify(spyCalculator).subtract(5, 3); // subtract(5, 3) 호좜 검증
        }
     }

     

     

    μ°Έκ³  λ¬Έν—Œ