Backend Language/TDD

[TDD Chapter7] λŒ€μ—­

chaerlo127 2023. 2. 12. 23:11
728x90

πŸ”’ λŒ€μ—­μ˜ ν•„μš”μ„±

[μ™ΈλΆ€ μš”μΈμ΄ ν…ŒμŠ€νŠΈμ— κ΄€μ—¬ν•˜λŠ” μ£Όμš” 예]

  • ν…ŒμŠ€νŠΈ λŒ€μƒμ—μ„œ 파일 μ‹œμŠ€ν…œ μ‚¬μš©
  • ν…ŒμŠ€νŠΈ λŒ€μƒμ—μ„œ DBλ‘œλΆ€ν„° 데이터λ₯Ό μ‘°νšŒν•˜κ±°λ‚˜ 데이터λ₯Ό μΆ”κ°€
  • ν…ŒμŠ€νŠΈ λŒ€μƒμ—μ„œ μ™ΈλΆ€μ˜ HTTP μ„œλ²„μ™€ 톡신

ν…ŒμŠ€νŠΈ λŒ€μƒμ΄ μœ„μ™€ 같은 μ™ΈλΆ€ μš”μΈμ— μ˜μ‘΄ν•˜μ—¬ μ‚¬μš©ν•˜λŠ” μ™ΈλΆ€ API μ„œλ²„κ°€ μΌμ‹œμ μœΌλ‘œ μž₯μ• κ°€ λ°œμƒν•˜λ©΄ ν…ŒμŠ€νŠΈλ₯Ό μ›ν™œν•˜κ²Œ μˆ˜ν–‰ν•  수 μ—†λ‹€. λ˜ν•œ, λ‚΄λΆ€ DBλ₯Ό μ‚¬μš©ν•˜λ”λΌλ„ 데이터 ꡬ성을 항상 κ°™κ²Œ μ§„ν–‰ν•˜κΈ°λŠ” μ–΄λ ΅λ‹€.

 

λ‹€μŒκ³Ό 같은 μ™ΈλΆ€ μš”μΈμ€ ν…ŒμŠ€νŠΈ μž‘μ„±μ„ μ–΄λ ΅κ²Œ λ§Œλ“€ 뿐만 μ•„λ‹ˆλΌ ν…ŒμŠ€νŠΈ 결과도 μ˜ˆμΈ‘ν•  수 μ—†κ²Œ λ§Œλ“ λ‹€.

 

ν…ŒμŠ€νŠΈ λŒ€μƒμ—μ„œ μ˜μ‘΄ν•˜λŠ” μš”μΈ λ•Œλ¬Έμ— ν…ŒμŠ€νŠΈκ°€ μ–΄λ €μšΈ λ•Œμ—λŠ” λŒ€μ—­μ„ μ¨μ„œ ν…ŒμŠ€νŠΈλ₯Ό μ§„ν–‰ν•œλ‹€. μ™ΈλΆ€ μš”μΈμœΌλ‘œ 인해 ν…ŒμŠ€νŠΈκ°€ μ–΄λ €μšΈ λ•Œ, μ™ΈλΆ€ μš”μΈμ„ λŒ€μ‹ ν•˜λŠ” λŒ€μ—­μ΄ μ™ΈλΆ€ μš”μΈμ„ λŒ€μ‹ ν•˜μ—¬ ν…ŒμŠ€νŠΈμ— μ°Έμ—¬ν•œλ‹€.

 

package testdriven.chap07;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static testdriven.chap07.CardValidity.THEFT;
import static testdriven.chap07.CardValidity.VALID;

public class AutoDebitRegisterTest {
    private AutoDebitRegister register;

    @BeforeEach
    void setUp(){
        CardNumberValidator validator = new CardNumberValidator();
        AutoDebitInfoRepository repository = new JPAAutoDebitInfoRepository();
        register = new AutoDebitRegister(validator, repository);
    }

    @Test
    void validCard(){
        // μ™ΈλΆ€ μ—…μ²΄μ—μ„œ 받은 ν…ŒμŠ€νŠΈμš© μœ νš¨ν•œ μΉ΄λ“œλ²ˆν˜Έ μ‚¬μš©
        // λŒ€μ—­μ„ μ‚¬μš©ν•˜μ—¬ ν…ŒμŠ€νŠΈ 진행
        AutoDebitReq req = new AutoDebitReq("user1", "123412341234");
        RegisterResult result = this.register.register(req);
        assertEquals(VALID, result.getValidity());
    }

    @Test
    void theftCard(){
        // μ™ΈλΆ€ μ—…μ²΄μ—μ„œ 받은 λ„λ‚œ ν…ŒμŠ€νŠΈμš© μΉ΄λ“œ 번호 μ‚¬μš©
        // λŒ€μ—­μ„ μ‚¬μš©ν•˜μ—¬ ν…ŒμŠ€νŠΈ 진행
        AutoDebitReq req = new AutoDebitReq("user1", "1234567890123456");
        RegisterResult result = this.register.register(req);
        assertEquals(THEFT, result.getValidity());
    }
}

 

 

πŸ”’ λŒ€μ—­μ„ μ‚¬μš©ν•œ μ™ΈλΆ€ 상황 흉내와 κ²°κ³Ό 검증 

예λ₯Ό λ“€μ–΄,

외뢀상황 ν‰λ‚΄μ˜ κ²½μš°μ—λŠ” μΉ΄λ“œ 정보 APIλ₯Ό λŒ€μ‹ ν•˜μ—¬ μœ νš¨ν•œ μΉ΄λ“œ 정보인지, λ„λ‚œ μΉ΄λ“œ 정보인지와 같은 상황을 ν‰λ‚΄λ‚΄κ±°λ‚˜ νŠΉμ • μ‚¬μš©μžμ— λŒ€ν•œ μžλ™ 이체 정보가 이미 λ“±λ‘λ˜μ–΄ μžˆκ±°λ‚˜ λ“±λ‘λ˜μ–΄ μžˆμ§€ μ•Šμ€ 상황을 흉내낸닀. 

package testdriven.chap07;

import java.util.HashMap;
import java.util.Map;

/**
 * μ™ΈλΆ€ 상황 흉내: νŠΉμ • μ‚¬μš©μžμ— λŒ€ν•œ μžλ™ 이체 정보가 이미 λ“±λ‘λ˜μ–΄ μžˆκ±°λ‚˜, μžˆμ§€ μ•Šμ€ 상황을 흉내냄.
 */
// AutoDebitInfoRepository 의 λŒ€μ—­
public class MemoryAutoDebitRepository implements AutoDebitInfoRepository{

    // μ˜μ†μ„±μ„ μ œκ³΅ν•˜μ§€λŠ” μ•Šμ§€λ§Œ, ν…ŒμŠ€νŠΈμ—μ„œ μ‚¬μš©ν•  수 μžˆμ„ 만큼의 κΈ°λŠ₯을 제곡
    private Map<String, AutoDebitInfo> infos = new HashMap<>();
    @Override
    public void save(AutoDebitInfo info) {
        infos.put(info.getUserIdx(), info);
    }

    @Override
    public AutoDebitInfo findOne(String userId) {
        return infos.get(userId);
    }
}
package testdriven.chap07;

/**
 * μ™ΈλΆ€ 상황 흉내: μΉ΄λ“œ 정보 API λ₯Ό λŒ€μ‹ ν•˜μ—¬ μœ νš¨ν•œ μΉ΄λ“œ 번호, λ„λ‚œ μΉ΄λ“œ λ²ˆν˜Έμ™€ 같은 상황을 흉내냄.
 */
public class StubCardNumberValidator extends CardNumberValidator{
    private String invalidNo;
    private String theftNo;

    // setInvalidNo둜 μ§€μ •λœ μΉ΄λ“œ λ²ˆν˜Έμ— λŒ€ν•΄μ„œλŠ” invalid, λ‚˜λ¨Έμ§€λŠ” valid
    public void setInvalidNo(String invalidNo){
        this.invalidNo = invalidNo;
    }

    public void setTheftNo(String theftNo){
        this.theftNo = theftNo;
    }

    @Override
    public CardValidity validate(String cardNumber) {
        // μœ νš¨ν•˜μ§€ μ•Šμ€ μΉ΄λ“œ 번호인 경우
        if(invalidNo != null && invalidNo.equals(cardNumber)){
            return CardValidity.INVALID;
        }

        // λ„λ‚œ μΉ΄λ“œ 번호인 경우
        if(theftNo != null && theftNo.equals(cardNumber)){
            return CardValidity.THEFT;
        }
        return CardValidity.VALID;
    }
}

 

이 뿐만 μ•„λ‹ˆλΌ, κ²°κ³Ό κ²€μ¦μœΌλ‘œ λŒ€μ—­μ„ μ‚¬μš©ν•  λ•Œ, λ©”λͺ¨λ¦¬λ₯Ό μ΄μš©ν•΄ μ €μž₯ κ²°κ³Όλ₯Ό 확인할 수 μžˆλ‹€. 

 

 

πŸ”’ λŒ€μ—­μ˜ μ’…λ₯˜

λŒ€μ—­ μ’…λ₯˜ μ„€λͺ…
μŠ€ν…(Stub) κ΅¬ν˜„μ„ λ‹¨μˆœν•œ κ²ƒμœΌλ‘œ λŒ€μ²΄, ν…ŒμŠ€νŠΈμ— 맞게 λ‹¨μˆœνžˆ μ›ν•˜λŠ” λ™μž‘μ„ μˆ˜ν–‰
κ°€μ§œ(Fake) μ œν’ˆμ—λŠ” μ ν•©ν•˜μ§€ μ•Šμ§€λ§Œ, μ‹€μ œ λ™μž‘ν•˜λŠ” κ΅¬ν˜„ 제곡
예] DB λŒ€μ‹  Map μ‚¬μš©ν•˜μ—¬ 데이터 μ €μž₯ν•˜λŠ” ν…ŒμŠ€νŠΈ 진행
슀파이(Spy) 호좜된 λ‚΄μ—­ 기둝, κΈ°λ‘ν•œ λ‚΄μš©μ€ ν…ŒμŠ€νŠΈ κ²°κ³Όλ₯Ό 검증할 λ•Œ μ‚¬μš©ν•˜λŠ” μŠ€ν…
λͺ¨μ˜ (Mock) κΈ°λŒ€ν•œ λŒ€λ‘œ μƒν˜Έμž‘μš©ν•˜λŠ”μ§€ ν–‰μœ„ 검증, κΈ°λŒ€ν•œλŒ€λ‘œ λ™μž‘ν•˜μ§€ μ•ŠμœΌλ©΄ 읡셉μ…₯ λ°œμƒ 

 

πŸ”’ νšŒμ› κ°€μž… κΈ°λŠ₯ κ΅¬ν˜„ (+ λŒ€μ—­ μ‚¬μš©)

κ΅¬ν˜„ν•˜κΈ° μ „ λͺ¨λ“  κΈ°λŠ₯을 μ„€κ²Œν•˜λŠ” 것은 λΆˆκ°€λŠ₯ν•˜λ‹€. ν•˜μ§€λ§Œ λ‹¨μœ„ κΈ°λŠ₯을 κ΅¬ν˜„ν•˜κΈ°μ— μ•žμ„œ μ–΄λ–€ ꡬ성 μš”μ†Œκ°€ ν•„μš”ν•œμ§€ κ³ λ―Όν•˜λŠ” 것은 의쑴 λŒ€μƒμ„ λ„μΆœν•  λ•Œ 도움이 λœλ‹€. 

 

πŸ–€ μ•½ν•œ μ•”ν˜Έμ—μ„œ 확인 κΈ°λŠ₯에 μŠ€ν… μ‚¬μš©

// ν…ŒμŠ€νŠΈ μ½”λ“œ 

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertThrows;

public class UserRegisterTest {
    private UserRegister userRegister;
    private StubWeakPasswordChecker stubWeakPasswordChecker = new StubWeakPasswordChecker();

    @BeforeEach
    void setUp(){
        userRegister = new UserRegister(stubWeakPasswordChecker);
    }

    @DisplayName("μ•½ν•œ μ•”ν˜Έλ©΄ μ‹€νŒ¨")
    @Test
    void weakPassword(){
        stubWeakPasswordChecker.setWeak(true); // μ•”ν˜Έκ°€ μ•½ν•˜λ„λ‘ 응닡

        assertThrows(WeakPasswordException.class, () ->
                userRegister.register("id", "pw", "email"));
    }
}

public class WeakPasswordException extends RuntimeException{
}

public interface WeakPasswordChecker {
    boolean checkPasswordWeak(String pw);
}

public class StubWeakPasswordChecker implements WeakPasswordChecker{
    private boolean weak;

    public void setWeak(boolean weak){
        this.weak = weak;
    }

    @Override
    public boolean checkPasswordWeak(String pw) {
        return weak;
    }
}

public class UserRegister {
    private WeakPasswordChecker passwordChecker;

    public UserRegister(WeakPasswordChecker passwordChecker){
        this.passwordChecker = passwordChecker;
    }
    public void register(String id, String pw, String email){
        if(passwordChecker.checkPasswordWeak(pw)){
            throw new WeakPasswordException();
        }
    }
}

 

πŸ–€ λ¦¬ν¬μ§€ν† λ¦¬λ₯Ό κ°€μ§œλ‘œ κ΅¬ν˜„

λŒ€μ—­μ˜ κ²°κ³Ό κ²€μ¦μœΌλ‘œ Map을 μ΄μš©ν•˜μ—¬ μ‹€μ œ DB μ ‘κ·Ό λŒ€μ‹ , μ½”λ“œ λ‚΄μ—μ„œ 정보λ₯Ό μ €μž₯ν•œ ν›„ μ €μž₯이 λ˜μ–΄ μžˆλ‹€λ©΄ μ—λŸ¬μ²˜λ¦¬λ₯Ό ν•˜λŠ” ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό μž‘μ„±ν•œ 것이닀.

// μ €μž₯ν•  정보λ₯Ό λ‹΄κ³  μžˆλŠ” Class
public class User {
    private String id;
    private String password;
    private String email;

    public User(String id, String password, String email){
        this.id = id;
        this.password = password;
        this.email = email;
    }

    public String getId() {
        return id;
    }

    public String getEmail() {
        return email;
    }
}

// DB μ ‘κ·Ό λͺ…λ Ήμ–΄
public interface UserRepository {
    void save(User user);
    User findById(String id);
}

// DB μ ‘κ·Ό μ½”λ“œ
public class MemoryUserRepository implements UserRepository{
    private Map<String, User> users = new HashMap<>();
    @Override
    public void save(User user) {
        users.put(user.getId(), user);
    }

    @Override
    public User findById(String id) {
        return users.get(id);
    }
}


public class UserRegister {
    private WeakPasswordChecker passwordChecker;
    private UserRepository userRepository;

    public UserRegister(WeakPasswordChecker passwordChecker, UserRepository userRepository){
        this.passwordChecker = passwordChecker;
        this.userRepository = userRepository;
    }
    public void register(String id, String pw, String email){
        if(passwordChecker.checkPasswordWeak(pw)){
            throw new WeakPasswordException();
        }
        // μΆ”κ°€λœ μ½”λ“œ 
        User user = userRepository.findById(id);
        if(user == null){
            throw new DupIdException();
        }
        userRepository.save(new User(id, pw, email));
    }
}

// ν…ŒμŠ€νŠΈ μ½”λ“œ
@DisplayName("이미 같은 아이디가 μ‘΄μž¬ν•˜λ©΄ κ°€μž… μ‹€νŒ¨")
    void dupIdExists(){
        // 이미 같은 아이디가 μžˆλŠ” μƒν™©μœΌλ‘œ λ§Œλ“€κΈ°
        fakeRepository.save(new User("id", "pw1", "email"));
        assertThrows(DupIdException.class,
                () -> userRegister.register("id", "pw2", "email"));
}

@DisplayName("같은 IDκ°€ μ—†μœΌλ©΄ κ°€μž… 성곡함")
    void noDupId_RegisterSuccess(){
        userRegister.register("id", "pw", "email");

        User savedUser = fakeRepository.findById("id");
        assertEquals("id", savedUser.getId());
        assertEquals("email", savedUser.getEmail());
}

 

πŸ–€ μ΄λ©”일 λ°œμ†‘ μ—¬λΆ€λ₯Ό ν™•μΈν•˜κΈ° μœ„ν•΄ 슀파이 μ‚¬μš©

public interface EmailNotifier {
    void sendRegisterEmail(String email);
}

public class SpyEmailNotifier implements EmailNotifier {

    private boolean called;
    private String email;

    public boolean isCalled() {
        return called;
    }

    public String getEmail() {
        return email;
    }

    @Override
    public void sendRegisterEmail(String email) {
        this.called = true; // test μ½”λ“œμ˜ assert True λ₯Ό ν†΅κ³Όμ‹œν‚€κΈ° μœ„ν•¨
        this.email = email;
    }
}

public class UserRegisterTest {
    private UserRegister userRegister;
    private StubWeakPasswordChecker stubWeakPasswordChecker = new StubWeakPasswordChecker();
    private MemoryUserRepository fakeRepository = new MemoryUserRepository();
    private SpyEmailNotifier spyEmailNotifier = new SpyEmailNotifier(); // μΆ”κ°€

    @BeforeEach
    void setUp(){
        userRegister = new UserRegister(stubWeakPasswordChecker, fakeRepository, spyEmailNotifier);
    }

   // ~~~~ μƒλž΅ ~~~~

    @DisplayName("κ°€μž…ν•˜λ©΄ 메일을 전솑함")
    @Test
    void whenRegisterThenSendMail(){
        userRegister.register("id", "pw", "email");

        assertTrue(spyEmailNotifier.isCalled());
        assertEquals(
                "email",
                spyEmailNotifier.getEmail()
        );
    }
}


  public void register(String id, String pw, String email){
        if(passwordChecker.checkPasswordWeak(pw)){
            throw new WeakPasswordException();
        }
        User user = userRepository.findById(id);
        if(user != null){
            throw new DupIdException();
        }
        userRepository.save(new User(id, pw, email));

        emailNotifier.sendRegisterEmail(email); // μ½”λ“œ μΆ”κ°€
    }

 

πŸ–€ λͺ¨μ˜ 객체둜 μŠ€ν…κ³Ό 슀파이 λŒ€μ²΄

λͺ¨μ˜ 객체λ₯Ό μ΄μš©ν•˜μ—¬ μ•žμ„œ μž‘μ„±ν•œ μ½”λ“œλ₯Ό λ‹€μ‹œ μž‘μ„±ν•˜κ³ μž ν•œλ‹€.

λͺ¨μ˜ κ°μ²΄λŠ” Mockito 도ꡬλ₯Ό μ΄μš©ν•˜μ—¬ λ‹€μ‹œ μž‘μ„±ν•  μ˜ˆμ •μΈλ°, Mockito의 λ‚΄μš©μ€ μ•„λž˜ 링크둜 정리λ₯Ό ν•΄ λ‘μ—ˆλ‹€. 

https://monynony0203.tistory.com/126

 

[μ°Έκ³ ] Mockito 기초 μ‚¬μš©λ²•

🌺 Mockitoλž€ λͺ¨μ˜ 객체 생성, 검증, μŠ€νŒμ„ μ§€μ›ν•˜λŠ” ν”„λ ˆμž„μ›Œν¬μ΄λ‹€. μ΄λŠ”, μΈκΈ°μžˆλŠ” μžλ°” λͺ¨μ˜ 객체 ν”„λ ˆμž„μ›Œν¬ 쀑 ν•˜λ‚˜λ‘œ, 이λ₯Ό 톡해 λŒ€μ—­μ„ 보닀 μ›ν™œν•˜κ²Œ μ‚¬μš©ν•  수 있게 λœλ‹€. 🌺 dependencies

monynony0203.tistory.com

 

 

package testdriven.chap07.login;

public class UserRegister {
    private WeakPasswordChecker passwordChecker;
    private UserRepository userRepository;
    private EmailNotifier emailNotifier;

    public UserRegister(WeakPasswordChecker passwordChecker, UserRepository userRepository, EmailNotifier spyEmailNotifier){
        this.passwordChecker = passwordChecker;
        this.userRepository = userRepository;
        this.emailNotifier = spyEmailNotifier;
    }


    public void register(String id, String pw, String email){
        if(passwordChecker.checkPasswordWeak(pw)){
            throw new WeakPasswordException();
        }
        User user = userRepository.findById(id);
        if(user != null){
            throw new DupIdException();
        }
        userRepository.save(new User(id, pw, email));

        emailNotifier.sendRegisterEmail(email);
    }
}

// spy: μ§„μ§œλ‘œ ν˜ΈμΆœλ˜μ—ˆλŠ”μ§€ 확인
    @DisplayName("κ°€μž…ν•˜λ©΄ 메일을 전솑함")
    @Test
    void whenRegisterThenSendMail(){
        userRegister.register("id", "pw", "email");

        ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); // String νƒ€μž…μ˜ 인자 보관
        then(mockEmailNotifier)
                .should().sendRegisterEmail(captor.capture());

        String realEmail = captor.getValue();
        assertEquals("email", realEmail);
    }

 

 

πŸ”’ 상황과 κ²°κ³Ό 확인을 μœ„ν•œ ν˜‘μ—… λŒ€μƒ(의쑴) λ„μΆœκ³Ό λŒ€μ—­ μ‚¬μš©

ν…ŒμŠ€νŠΈλŠ” νŠΉμ •ν•œ μƒν™©μ—μ„œ κΈ°λŠ₯을 μ‹€ν–‰ν•˜κ³  κ²°κ³Όλ₯Ό ν™•μΈν•œλ‹€. ν•˜μ§€λ§Œ, μ‹€μ œ κ΅¬ν˜„μ„ μ΄μš©ν•˜λ©΄ 상황을 λ§Œλ“€κΈ° μ–΄λ €μšΈ λ•Œκ°€ μžˆλ‹€. 예λ₯Ό λ“€λ©΄ λ©”μ†Œλ“œ 내뢀에 μ™ΈλΆ€ μΉ΄λ“œ 정보 APIλ₯Ό μ—°λ™ν•˜μ—¬ retuurn 을 ν•˜κ²Œ 되면 μœ νš¨ν•˜μ§€ μ•Šμ€ μΉ΄λ“œλ²ˆν˜Έλ₯Ό μœ„ν•œ 상황을 κ΅¬μ„±ν•˜κΈ° μ–΄λ ΅λ‹€. 

 

이렇기 λ•Œλ¬Έμ—, κ΅¬ν˜„/μ œμ–΄ν•˜κΈ° νž˜λ“  κ΅¬ν˜„μƒν™©μ΄ μ‘΄μž¬ν•˜λ©΄ λ‹€μŒκ³Ό 같이 μ˜μ‘΄μ„ λ„μΆœν•˜κ³  이λ₯Ό λŒ€μ—­μœΌλ‘œ λŒ€μ‹ ν•  수 μžˆλ‹€. 

  • μ œμ–΄ν•˜κΈ° νž˜λ“  μ™ΈλΆ€ 상황을 별도 νƒ€μž…μœΌλ‘œ 뢄리
  • ν…ŒμŠ€νŠΈ μ½”λ“œλŠ” λ³„λ„λ‘œ λΆ„λ¦¬ν•œ νƒ€μž…μ˜ λŒ€μ—­μ„ 생성
  • μƒμ„±ν•œ λŒ€μ—­μ„ ν…ŒμŠ€νŠΈ λŒ€μƒμ˜ μƒμ„±μž 등을 μ΄μš©ν•˜μ—¬ 전달
  • λŒ€μ—­μ„ μ΄μš©ν•˜μ—¬ 상황 ꡬ성

 

πŸ”’ λŒ€μ—­κ³Ό 개발 속도

TDD κ³Όμ •μ—μ„œ λŒ€μ—­μ„ μ‚¬μš©ν•˜μ§€ μ•Šκ³  μ‹€μ œ κ΅¬ν˜„μ„ ν•œλ‹€λ©΄ λ§Žμ€ 문제 상황이 λ°œμƒν•  것이닀.

 

κ·Έλ ‡κΈ° λ•Œλ¬Έμ— λŒ€μ—­μ„ μ‚¬μš©ν•˜λ©΄  μ‹€μ œ κ΅¬ν˜„ 없이도 λ‹€μ–‘ν•œ 상황에 λŒ€ν•΄ ν…ŒμŠ€νŠΈλ₯΄ ν•  수 μžˆλ‹€. μ™ΈλΆ€μ˜ μΉ΄λ“œ 정보 제곡 API와 연동할 수 μ—†λŠ” κ²½μš°μ—λ„ ν…ŒμŠ€νŠΈλ₯Ό 진행할 수 μžˆλŠ” 것이닀. 

 

λ˜ν•œ, μ‹€μ œ κ΅¬ν˜„μ΄ 없어도 μ‹€ν–‰ κ²°κ³Όλ₯Ό λ°”λ‘œ 확인할 수 μžˆλ‹€. 

 

λŒ€μ—­μ€ μ˜μ‘΄ν•˜λŠ” λŒ€μƒ (DB, μ™ΈλΆ€ API λ“±)을 κ΅¬ν˜„ν•˜μ§€ μ•Šμ•„λ„ ν…ŒμŠ€νŠΈλ₯Ό μ™„μ„±ν•  수 있게 λ§Œλ“€μ–΄μ£Όκ³ , λŒ€κΈ° μ‹œκ°„μ„ 쀄여주어 κ°œλ°œμ†λ„λŠ” ν–₯μƒμ‹œν‚¬ 수 μžˆλ‹€.

 

 

πŸ”’ λͺ¨μ˜ 객체λ₯Ό κ³Όν•˜κ²Œ μ‚¬μš©ν•˜μ§€ μ•ŠκΈ°

λͺ¨μ˜ κ°μ²΄λŠ” μŠ€ν…κ³Ό 슀파이λ₯Ό μ§€μ›ν•˜λ―€λ‘œ λŒ€μ—­μœΌλ‘œ λͺ¨μ˜ 객체λ₯Ό 많이 μ‚¬μš©ν•œλ‹€. ν•˜μ§€λ§Œ, λͺ¨μ˜ 객체λ₯Ό κ³Όν•˜κ²Œ μ‚¬μš©ν•˜λ©΄ 였히렀 ν…ŒμŠ€νŠΈ μ½”λ“œκ°€ λ³΅μž‘ν•΄μ§€λŠ” κ²½μš°λ„ λ°œμƒν•  수 μžˆλ‹€. 

 

λͺ¨μ˜ 객체λ₯Ό μ΄μš©ν•˜λ©΄ λŒ€μ—­ 클래슀λ₯Ό λ§Œλ“€μ§€ μ•Šμ•„λ„ λ˜λ‹ˆκΉŒ νŽΈν•  수 μžˆμ§€λ§Œ, κ²°κ³Ό 값을 ν™•μΈν•˜λŠ” μˆ˜λ‹¨μœΌλ‘œ λͺ¨μ˜ 객체λ₯Ό μ‚¬μš©ν•˜κ²Œ 되면 κ²°κ³Ό 검증 μ½”λ“œκ°€ 길어지고 λ³΅μž‘ν•΄μ§„λ‹€. 

 

기본적으둜 λͺ¨μ˜ κ°μ²΄λŠ” λ©”μ†Œλ“œ 호좜 μ—¬λΆ€λ₯Ό κ²€μ¦ν•˜λŠ” μˆ˜λ‹¨μ΄κΈ° λ•Œλ¬Έμ— ν…ŒμŠ€νŠΈ λŒ€μƒκ³Ό λͺ¨μ˜ 객체 κ°„μ˜ μƒν˜Έμž‘μš©μ΄ 쑰금만 λ°”λ€Œμ–΄λ„ ν…ŒμŠ€νŠΈκ°€ 깨지기 쉽닀.

 

특히 DAOλ‚˜ Repository와같이 μ €μž₯μ†Œμ— λŒ€ν•œ λŒ€μ—­μ€ λͺ¨μ˜ 객체λ₯Ό μ‚¬μš©ν•˜λŠ” 것보닀 λ©”λͺ¨λ¦¬λ₯Ό μ΄μš©ν•΄ κ°€μ§œ κ΅¬ν˜„μ„ μ‚¬μš©ν•˜λŠ” 것이 ν…ŒμŠ€νŠΈ μ½”λ“œ 관리할 λ•Œ μœ λ¦¬ν•˜λ‹€. 

728x90