diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/AutoDebitInfoRepository.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/AutoDebitInfoRepository.java" new file mode 100644 index 0000000..c8c742a --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/AutoDebitInfoRepository.java" @@ -0,0 +1,8 @@ +package study.tdd.chap07; + +public class AutoDebitInfoRepository { + /* + void save(AutoDebitInfo info); + AutoDebitInfo findOne(String userId); + */ +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/AutoDebitRegister.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/AutoDebitRegister.java" new file mode 100644 index 0000000..8adb6f1 --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/AutoDebitRegister.java" @@ -0,0 +1,34 @@ +package study.tdd.chap07; + +import java.time.LocalDateTime; + +public class AutoDebitRegister { + /* + private CardNumberValidator validator; + private AutoDebitInfoRepository repository; + + public AutoDebitRegister(CardNumberValidator validator, AutoDebitInfoRepository repository) { + this.validator = validator; + this.repository = repository; + } + + public RegisterResult register(AutoDebitReq req) { + CardValidity validity = validator.validate(req.getCardNumber()); + + if (validity != CardValidity.VALID) { + return RegisterResult.error(validity); + } + + AutoDebitInfo info = repository.findOne(req.getUserId()); + + if (info != null) { + info.changeCardNumber(req.getCardNumber()); + } else { + AutoDebitInfo newInfo = new AutoDebitInfo(req.getUserId(), req.getCardNumber(), LocalDateTime.now()); + repository.save(newInfo); + } + + return RegisterResult.success(); + } + */ +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/CardNumberValidator.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/CardNumberValidator.java" new file mode 100644 index 0000000..870c956 --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/CardNumberValidator.java" @@ -0,0 +1,38 @@ +package study.tdd.chap07; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +public class CardNumberValidator { + /* + public CardValidity validate(String cardNumber) { + HttpClient httpClient = HttpClient.newHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create("https://some-external-pg.com/card")) + .header("Content-Type", "text/plain") + .POST(HttpRequest.BodyPublishers.ofString(cardNumber)) + .build(); + + try { + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + switch (response.body()) { + case "ok": + return CardValidity.VALID; + case "bad": + return CardValidity.INVALID; + case "expired": + return CardValidity.EXPIRED; + case "theft": + return CardValidity.THEFT; + default: + return CardValidity.UNKNOWN; + } + } catch (IOException | InterruptedException exception) { + return CardValidity.ERROR; + } + } + */ +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/MemoryAutoDebitInfoRepository.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/MemoryAutoDebitInfoRepository.java" new file mode 100644 index 0000000..b9377ba --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/MemoryAutoDebitInfoRepository.java" @@ -0,0 +1,20 @@ +package study.tdd.chap07; + +import java.util.HashMap; + +/* +public class MemoryAutoDebitInfoRepository implements AutoDebitInfoRepository { + + private Map infos = new HashMap<>(); + + @Override + public void save(AutoDebitInfo info) { + infos.put(info.getUserId(), info); + } + + @Override + public AutoDebitInfo findOne(String userId) { + return infos.get(userId); + } +} +*/ diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/StubCardNumberValidator.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/StubCardNumberValidator.java" new file mode 100644 index 0000000..dd19ff4 --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/StubCardNumberValidator.java" @@ -0,0 +1,27 @@ +package study.tdd.chap07; + +public class StubCardNumberValidator extends CardNumberValidator { + /* + private String invalidNo; + private String theftNo; + + 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; + } + */ +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/DupIdException.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/DupIdException.java" new file mode 100644 index 0000000..bef9b5d --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/DupIdException.java" @@ -0,0 +1,4 @@ +package study.tdd.chap07.join; + +public class DupIdException extends RuntimeException { +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/EmailNotifier.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/EmailNotifier.java" new file mode 100644 index 0000000..fb0ea8a --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/EmailNotifier.java" @@ -0,0 +1,5 @@ +package study.tdd.chap07.join; + +public interface EmailNotifier { + void sendRegisterEmail(String email); +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/MemoryUserRepository.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/MemoryUserRepository.java" new file mode 100644 index 0000000..516cd48 --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/MemoryUserRepository.java" @@ -0,0 +1,20 @@ +package study.tdd.chap07.join; + +import study.tdd.chap07.join.UserRepository; + +import java.util.HashMap; +import java.util.Map; + +public class MemoryUserRepository implements UserRepository { + private Map users = new HashMap<>(); + + @Override + public void save(User user) { + users.put(user.getId(), user); + } + + @Override + public User findById(String id) { + return users.get(id); + } +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/SpyEmailNotifier.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/SpyEmailNotifier.java" new file mode 100644 index 0000000..c62a055 --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/SpyEmailNotifier.java" @@ -0,0 +1,20 @@ +package study.tdd.chap07.join; + +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; + this.email = email; + } +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/StubWeakPasswordChecker.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/StubWeakPasswordChecker.java" new file mode 100644 index 0000000..29274c6 --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/StubWeakPasswordChecker.java" @@ -0,0 +1,14 @@ +package study.tdd.chap07.join; + +public class StubWeakPasswordChecker implements WeakPasswordChecker { + private boolean weak; + + public void setWeak(boolean weak) { + this.weak = weak; + } + + @Override + public boolean checkPasswordWeak(String pw) { + return weak; + } +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/User.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/User.java" new file mode 100644 index 0000000..744ff93 --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/User.java" @@ -0,0 +1,21 @@ +package study.tdd.chap07.join; + +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; + } +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/UserRegister.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/UserRegister.java" new file mode 100644 index 0000000..f1d4a80 --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/UserRegister.java" @@ -0,0 +1,25 @@ +package study.tdd.chap07.join; + +public class UserRegister { + private WeakPasswordChecker passwordChecker; + private UserRepository userRepository; + private EmailNotifier emailNotifier; + + public UserRegister(WeakPasswordChecker passwordChecker, UserRepository userRepository, EmailNotifier emailNotifier) { + this.passwordChecker = passwordChecker; + this.userRepository = userRepository; + this.emailNotifier = emailNotifier; + } + + 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); + } +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/UserRepository.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/UserRepository.java" new file mode 100644 index 0000000..57b5731 --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/UserRepository.java" @@ -0,0 +1,7 @@ +package study.tdd.chap07.join; + +public interface UserRepository { + void save(User user); + + User findById(String id); +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/WeakPasswordChecker.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/WeakPasswordChecker.java" new file mode 100644 index 0000000..bd0008b --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/WeakPasswordChecker.java" @@ -0,0 +1,5 @@ +package study.tdd.chap07.join; + +public interface WeakPasswordChecker { + boolean checkPasswordWeak(String pw); +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/WeakPasswordException.java" "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/WeakPasswordException.java" new file mode 100644 index 0000000..e569b33 --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/main/java/study/tdd/chap07/join/WeakPasswordException.java" @@ -0,0 +1,4 @@ +package study.tdd.chap07.join; + +public class WeakPasswordException extends RuntimeException { +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/AutoDebitRegisterTest.java" "b/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/AutoDebitRegisterTest.java" new file mode 100644 index 0000000..2ffb07b --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/AutoDebitRegisterTest.java" @@ -0,0 +1,35 @@ +package study.tdd.chap07; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +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", "1234123412341234"); + 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()); + } + */ +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/AutoDebitRegister_Fake_Test.java" "b/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/AutoDebitRegister_Fake_Test.java" new file mode 100644 index 0000000..6a0f193 --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/AutoDebitRegister_Fake_Test.java" @@ -0,0 +1,43 @@ +package study.tdd.chap07; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class AutoDebitRegister_Fake_Test { + /* + private AutoDebitRegister register; + private StubCardNumberValidator cardNumberValidator; + private MemoryAutoDebitInfoRepository repository; + + @BeforeEach + void setUp() { + cardNumberValidator = new StubCardNumberValidator(); + repository = new MemoryAutoDebitInfoRepository(); + register = new AutoDebitRegister(cardNumberValidator, repository); + } + + @Test + void alreadyRegistered_InfoUpdated() { + repository.save(new AutoDebitInfo("user1", "111222333444", LocalDateTime.now())); + + AutoDebitReq req = new AutoDebitReq("user1", "123456789012"); + RegisterResult result = this.register.register(req); + + AutoDebitInfo saved = repository.findOne("user1"); + assertEquals("123456789012", saved.getCardNumber()); + } + + @Test + void notYetRegistered_newInfoRegistered() { + AutoDebitReq req = new AutoDebitReq("user1", "1234123412341234"); + RegisterResult result = this.register.register(req); + + AutoDebitInfo saved = repository.findOne("user1"); + assertEquals("1234123412341234", saved.getCardNumber()); + } + */ +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/AutoDebitRegister_Stub_Test.java" "b/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/AutoDebitRegister_Stub_Test.java" new file mode 100644 index 0000000..df093ed --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/AutoDebitRegister_Stub_Test.java" @@ -0,0 +1,41 @@ +package study.tdd.chap07; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class AutoDebitRegister_Stub_Test { + /* + private AutoDebitRegister register; + private StubCardNumberValidator stubValidator; + private StubAutoDebitInfoRepository stubRepository; + + @BeforeEach + void setUp() { + stubValidator = new StubCardNumberValidator(); + stubRepository = new StubAutoDebitInfoRepository(); + register = new AutoDebitRegister(stubValidator, stubRepository); + } + + @Test + void invalidCard() { + stubValidator.setInvalidNo("111122223333"); + + AutoDebitReq req = new AutoDebitReq("user1", "111122223333"); + RegisterResult result = register.register(req); + + assertEquals(INVALID, result.getValidity()); + } + + @Test + void theftCard() { + stubValidator.setTheftNo("1234567890123456"); + + AutoDebitReq req = new AutoDebitReq("user1", "1234567890123456"); + RegisterResult result = register.register(req); + + assertEquals(CardValidity.THEFT, result.getValidity()); + } + */ +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/UserRegisterMockTest.java" "b/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/UserRegisterMockTest.java" new file mode 100644 index 0000000..914c692 --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/UserRegisterMockTest.java" @@ -0,0 +1,57 @@ +package study.tdd.chap07; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.BDDMockito; +import org.mockito.Mockito; +import study.tdd.chap07.join.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class UserRegisterMockTest { + private UserRegister userRegister; + private WeakPasswordChecker mockPasswordChecker = Mockito.mock(WeakPasswordChecker.class); + private MemoryUserRepository fakeRepository = new MemoryUserRepository(); + private EmailNotifier mockEmailNotifier = Mockito.mock(EmailNotifier.class); + + @BeforeEach + void setUp() { + userRegister = new UserRegister(mockPasswordChecker, fakeRepository, mockEmailNotifier); + } + + @DisplayName("약한 암호면 가입 실패") + @Test + void weakPassword() { + BDDMockito.given(mockPasswordChecker.checkPasswordWeak("pw")).willReturn(true); + + assertThrows(WeakPasswordException.class, () -> { + userRegister.register("id", "pw", "email"); + }); + } + + @DisplayName("회원 가입시 암호 검사 수행함") + @Test + void checkPassword() { + userRegister.register("id", "pw", "email"); + + BDDMockito.then(mockPasswordChecker) + .should() + .checkPasswordWeak(BDDMockito.anyString()); + } + + @DisplayName("가입하면 메일을 전송함") + @Test + void whenRegisterThenSendMail() { + userRegister.register("id", "pw", "email"); + + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + BDDMockito.then(mockEmailNotifier) + .should().sendRegisterEmail(captor.capture()); + + String realEmail = captor.getValue(); + assertEquals("email@email.com", realEmail); + } +} diff --git "a/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/UserRegisterTest.java" "b/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/UserRegisterTest.java" new file mode 100644 index 0000000..2513ada --- /dev/null +++ "b/\352\271\200\354\227\260\354\247\200/src/test/java/study/tdd/chap07/UserRegisterTest.java" @@ -0,0 +1,60 @@ +package study.tdd.chap07; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import study.tdd.chap07.join.*; + +import static org.junit.jupiter.api.Assertions.*; + +public class UserRegisterTest { + private UserRegister userRegister; + private StubWeakPasswordChecker stubPasswordChecker = new StubWeakPasswordChecker(); + private MemoryUserRepository fakeRepository = new MemoryUserRepository(); + private SpyEmailNotifier spyEmailNotifier = new SpyEmailNotifier(); + + @BeforeEach + void setUp() { + userRegister = new UserRegister(stubPasswordChecker, fakeRepository, spyEmailNotifier); + } + + @DisplayName("약한 암호면 가입 실패") + @Test + void weakPassword() { + stubPasswordChecker.setWeak(true); // 암호가 약하다고 응답하도록 설정 + + assertThrows(WeakPasswordException.class, () -> { + userRegister.register("id", "pw", "email"); + }); + } + + @DisplayName("이미 같은 ID가 존재하면 가입 실패") + @Test + void dupIdExists() { + // 이미 같은 ID 존재하는 상황 만들기 + fakeRepository.save(new User("id", "pw1", "email@email.com")); + + assertThrows(DupIdException.class, () -> { + userRegister.register("id", "pw2", "email"); + }); + } + + @DisplayName("같은 ID가 없으면 가입 성공함") + @Test + void noDupId_RegisterSuccess() { + userRegister.register("id", "pw", "email"); + + User savedUser = fakeRepository.findById("id"); // 가입 결과 확인 + assertEquals("id", savedUser.getId()); + assertEquals("email", savedUser.getEmail()); + } + + @DisplayName("가입하면 메일을 전송함") + @Test + void whenRegisterThenSendMail() { + userRegister.register("id", "pw", "email@email.com"); + + assertTrue(spyEmailNotifier.isCalled()); + assertEquals("email@email.com", spyEmailNotifier.getEmail()); + } +}