diff --git a/build.gradle b/build.gradle index 48e760690..66b4bc22a 100644 --- a/build.gradle +++ b/build.gradle @@ -28,12 +28,17 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.mindrot:jbcrypt:0.3m' + developmentOnly 'org.springframework.boot:spring-boot-devtools' + runtimeOnly 'com.h2database:h2' runtimeOnly 'mysql:mysql-connector-java' + testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.junit.jupiter:junit-jupiter-api' + testImplementation 'org.jmockit:jmockit:1.24' testImplementation('org.springframework.boot:spring-boot-starter-test') { exclude group: 'junit' } diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/article/dto/ArticleResponse.java b/src/main/java/com/woowacourse/zzazanstagram/model/article/dto/ArticleResponse.java index 0975c024d..e218e83ce 100644 --- a/src/main/java/com/woowacourse/zzazanstagram/model/article/dto/ArticleResponse.java +++ b/src/main/java/com/woowacourse/zzazanstagram/model/article/dto/ArticleResponse.java @@ -1,6 +1,7 @@ package com.woowacourse.zzazanstagram.model.article.dto; import java.time.LocalDateTime; +import java.util.Objects; public class ArticleResponse { private Long id; @@ -112,4 +113,23 @@ public ArticleResponse build() { return new ArticleResponse(id, image, contents, nickName, profileImage, createdDate, lastModifiedDate); } } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ArticleResponse response = (ArticleResponse) o; + return Objects.equals(id, response.id) && + Objects.equals(image, response.image) && + Objects.equals(contents, response.contents) && + Objects.equals(nickName, response.nickName) && + Objects.equals(profileImage, response.profileImage) && + Objects.equals(createdDate, response.createdDate) && + Objects.equals(lastModifiedDate, response.lastModifiedDate); + } + + @Override + public int hashCode() { + return Objects.hash(id, image, contents, nickName, profileImage, createdDate, lastModifiedDate); + } } diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/Member.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/Member.java index caa034bfe..abdcd2b6c 100644 --- a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/Member.java +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/Member.java @@ -4,6 +4,7 @@ import com.woowacourse.zzazanstagram.model.member.domain.vo.*; import javax.persistence.Entity; +import java.util.Objects; @Entity public class Member extends BaseEntity { diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Email.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Email.java index aab7e5256..f5644b9cd 100644 --- a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Email.java +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Email.java @@ -4,6 +4,7 @@ import javax.persistence.Column; import javax.persistence.Embeddable; +import java.util.Objects; @Embeddable public class Email { @@ -37,4 +38,17 @@ private boolean isMismatch(String email) { public String getEmail() { return email; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Email email1 = (Email) o; + return Objects.equals(email, email1.email); + } + + @Override + public int hashCode() { + return Objects.hash(email); + } } diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Name.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Name.java index 93e3bbbb7..28289ad91 100644 --- a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Name.java +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Name.java @@ -4,6 +4,7 @@ import javax.persistence.Column; import javax.persistence.Embeddable; +import java.util.Objects; @Embeddable public class Name { @@ -37,4 +38,17 @@ private boolean isMismatch(String name) { public String getName() { return name; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Name name1 = (Name) o; + return Objects.equals(name, name1.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } } diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/NickName.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/NickName.java index aaa5a26f1..ea4223290 100644 --- a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/NickName.java +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/NickName.java @@ -4,6 +4,7 @@ import javax.persistence.Column; import javax.persistence.Embeddable; +import java.util.Objects; @Embeddable public class NickName { @@ -37,4 +38,17 @@ private boolean isMismatch(String name) { public String getNickName() { return nickName; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + NickName nickName1 = (NickName) o; + return Objects.equals(nickName, nickName1.nickName); + } + + @Override + public int hashCode() { + return Objects.hash(nickName); + } } diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Password.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Password.java index 542b0bf44..2f9b47752 100644 --- a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Password.java +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/Password.java @@ -5,6 +5,7 @@ import javax.persistence.Column; import javax.persistence.Embeddable; +import java.util.Objects; @Embeddable public class Password { @@ -56,4 +57,17 @@ static boolean isMatch(String password, String hashed) { return BCrypt.checkpw(password, hashed); } } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Password password1 = (Password) o; + return Objects.equals(password, password1.password); + } + + @Override + public int hashCode() { + return Objects.hash(password); + } } diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/ProfileImage.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/ProfileImage.java index 5c8b7fc10..43e16d071 100644 --- a/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/ProfileImage.java +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/domain/vo/ProfileImage.java @@ -2,6 +2,7 @@ import javax.persistence.Column; import javax.persistence.Embeddable; +import java.util.Objects; @Embeddable public class ProfileImage { @@ -23,4 +24,17 @@ public static ProfileImage of(final String url) { public String getUrl() { return url; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ProfileImage that = (ProfileImage) o; + return Objects.equals(url, that.url); + } + + @Override + public int hashCode() { + return Objects.hash(url); + } } diff --git a/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberResponse.java b/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberResponse.java index 28396f266..7eda7973b 100644 --- a/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberResponse.java +++ b/src/main/java/com/woowacourse/zzazanstagram/model/member/dto/MemberResponse.java @@ -1,5 +1,7 @@ package com.woowacourse.zzazanstagram.model.member.dto; +import java.util.Objects; + public class MemberResponse { private String nickName; private String name; @@ -44,4 +46,20 @@ public String getProfileImage() { public void setProfileImage(String profileImage) { this.profileImage = profileImage; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MemberResponse that = (MemberResponse) o; + return Objects.equals(nickName, that.nickName) && + Objects.equals(name, that.name) && + Objects.equals(email, that.email) && + Objects.equals(profileImage, that.profileImage); + } + + @Override + public int hashCode() { + return Objects.hash(nickName, name, email, profileImage); + } } diff --git a/src/test/java/com/woowacourse/zzazanstagram/model/article/ArticleConstant.java b/src/test/java/com/woowacourse/zzazanstagram/model/article/ArticleConstant.java index 26fd9e9d2..c57eb5b01 100644 --- a/src/test/java/com/woowacourse/zzazanstagram/model/article/ArticleConstant.java +++ b/src/test/java/com/woowacourse/zzazanstagram/model/article/ArticleConstant.java @@ -4,4 +4,8 @@ public class ArticleConstant { public static final String IMAGE_URL = "https://image.shutterstock.com/image-photo/white-transparent-leaf-on-mirror-600w-1029171697.jpg"; public static final String CONTENTS = "글의 내용이란다"; public static final String HASHTAG = "#아이크 #닉 #뚱이 #제이 #에헴"; + public static final String EMAIL = "email@email.com"; + public static final String NAME = "개똥이"; + public static final String NICKNAME = "말똥이"; + public static final String PASSWORD = "!#Password12"; } diff --git a/src/test/java/com/woowacourse/zzazanstagram/model/article/service/ArticleServiceTest.java b/src/test/java/com/woowacourse/zzazanstagram/model/article/service/ArticleServiceTest.java new file mode 100644 index 000000000..e74ac8e98 --- /dev/null +++ b/src/test/java/com/woowacourse/zzazanstagram/model/article/service/ArticleServiceTest.java @@ -0,0 +1,97 @@ +package com.woowacourse.zzazanstagram.model.article.service; + +import com.woowacourse.zzazanstagram.model.article.domain.Article; +import com.woowacourse.zzazanstagram.model.article.domain.vo.Contents; +import com.woowacourse.zzazanstagram.model.article.domain.vo.Image; +import com.woowacourse.zzazanstagram.model.article.dto.ArticleRequest; +import com.woowacourse.zzazanstagram.model.article.dto.ArticleResponse; +import com.woowacourse.zzazanstagram.model.article.repository.ArticleRepository; +import com.woowacourse.zzazanstagram.model.member.domain.Member; +import com.woowacourse.zzazanstagram.model.member.service.MemberService; +import mockit.Deencapsulation; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.Arrays; +import java.util.List; + +import static com.woowacourse.zzazanstagram.model.article.ArticleConstant.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@ExtendWith(SpringExtension.class) +class ArticleServiceTest { + private Image image; + private Contents contents; + private Member member; + + @InjectMocks // @Mock, @Spy가 붙은 목 객체를 자신의 멤버 클래스와 일치하면 주입시킨다 + private ArticleService articleService; + + @Mock + private MemberService memberService; + + @Mock + private ArticleRepository articleRepository; + + @BeforeEach + void setUp() { + image = Image.of(IMAGE_URL); + contents = Contents.of(CONTENTS); + member = Member.MemberBuilder.aMember() + .email(EMAIL) + .name(NAME) + .nickName(NICKNAME) + .password(PASSWORD) + .profile(IMAGE_URL) + .build(); + } + + @Test + public void 모든_게시글들이_select되는지_테스트() { // TODO 나중에 팔로우 중인 게시글만 뽑아내도록 바꿔야 함 + // given + Article article = new Article(image, contents, member); + ArticleResponse response = Deencapsulation.invoke(ArticleAssembler.class, "toDto", article); + List
articles = Arrays.asList(article, article, article); + + given(articleRepository.findAllByOrderByIdDesc()).willReturn(articles); + + // when + List articleResponses = articleService.getArticleResponses(); + + // then + assertThat(articleResponses).isEqualTo(Arrays.asList(response, response, response)); + /*ArticleResponse resultElement = ArticleResponse.ArticleResponseBuilder.anArticleResponse() + .id(article.getId()) + .image(article.getImageValue()) + .contents(article.getContentsValue()) + .nickName(article.getAuthor().getNickNameValue()) + .profileImage(article.getAuthor().getProfileImageValue()) + .createdDate(article.getCreatedDate()) + .lastModifiedDate(article.getLastModifiedDate()) + .build();*/ + } + + @Test + public void save() { + // given + ArticleRequest articleRequest = new ArticleRequest(IMAGE_URL, CONTENTS, HASHTAG); + Article article = Deencapsulation.invoke(ArticleAssembler.class, "toEntity", articleRequest, member); + + given(memberService.findMemberByEmail(EMAIL)).willReturn(member); + given(articleRepository.save(article)).willReturn(article); + + // when + articleService.save(articleRequest, EMAIL); + + // then + verify(articleRepository, times(1)).save(article); + } + +} \ No newline at end of file diff --git a/src/test/java/com/woowacourse/zzazanstagram/model/member/service/LoginServiceTest.java b/src/test/java/com/woowacourse/zzazanstagram/model/member/service/LoginServiceTest.java new file mode 100644 index 000000000..ab1cd596e --- /dev/null +++ b/src/test/java/com/woowacourse/zzazanstagram/model/member/service/LoginServiceTest.java @@ -0,0 +1,80 @@ +package com.woowacourse.zzazanstagram.model.member.service; + +import com.woowacourse.zzazanstagram.model.member.domain.Member; +import com.woowacourse.zzazanstagram.model.member.domain.vo.Email; +import com.woowacourse.zzazanstagram.model.member.dto.MemberLoginRequest; +import com.woowacourse.zzazanstagram.model.member.dto.MemberResponse; +import com.woowacourse.zzazanstagram.model.member.exception.MemberLoginFailException; +import com.woowacourse.zzazanstagram.model.member.repository.MemberRepository; +import mockit.Deencapsulation; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.Optional; + +import static com.woowacourse.zzazanstagram.model.article.ArticleConstant.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.BDDMockito.given; + +@ExtendWith(SpringExtension.class) +class LoginServiceTest { + private Email email; + private Member member; + + @InjectMocks + private LoginService loginService; + + @Mock + private MemberRepository memberRepository; + + @BeforeEach + void setUp() { + email = Email.of(EMAIL); + member = Member.MemberBuilder.aMember() + .email(EMAIL) + .name(NAME) + .nickName(NICKNAME) + .password(PASSWORD) + .profile(IMAGE_URL) + .build(); + } + + @Test + public void 정상적인_로그인_테스트() { + // given + MemberLoginRequest request = new MemberLoginRequest(EMAIL, PASSWORD); + + MemberResponse memberResponse = Deencapsulation.invoke(MemberAssembler.class, "assemble", member); + given(memberRepository.findByEmail(email)).willReturn(Optional.of(member)); + + // then + assertThat(loginService.find(request)).isEqualTo(memberResponse); + } + + @Test + public void 존재하지_않는_정보로_로그인하는_경우_테스트() { + // given + MemberLoginRequest request = new MemberLoginRequest(EMAIL, PASSWORD); + + given(memberRepository.findByEmail(email)).willReturn(Optional.empty()); + + // then + assertThrows(MemberLoginFailException.class, () -> loginService.find(request)); + } + + @Test + public void 비밀번호가_일치하지_않는_경우_테스트() { + // given + MemberLoginRequest request = new MemberLoginRequest(EMAIL, "WRONG" + PASSWORD); + + given(memberRepository.findByEmail(email)).willReturn(Optional.of(member)); + + // then + assertThrows(MemberLoginFailException.class, () -> loginService.find(request)); + } +} \ No newline at end of file diff --git a/src/test/java/com/woowacourse/zzazanstagram/model/member/service/MemberServiceTest.java b/src/test/java/com/woowacourse/zzazanstagram/model/member/service/MemberServiceTest.java new file mode 100644 index 000000000..2907b3299 --- /dev/null +++ b/src/test/java/com/woowacourse/zzazanstagram/model/member/service/MemberServiceTest.java @@ -0,0 +1,107 @@ +package com.woowacourse.zzazanstagram.model.member.service; + +import com.woowacourse.zzazanstagram.model.member.domain.Member; +import com.woowacourse.zzazanstagram.model.member.domain.vo.Email; +import com.woowacourse.zzazanstagram.model.member.domain.vo.NickName; +import com.woowacourse.zzazanstagram.model.member.dto.MemberSignUpRequest; +import com.woowacourse.zzazanstagram.model.member.exception.MemberNotFoundException; +import com.woowacourse.zzazanstagram.model.member.exception.MemberSaveException; +import com.woowacourse.zzazanstagram.model.member.repository.MemberRepository; +import mockit.Deencapsulation; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.Optional; + +import static com.woowacourse.zzazanstagram.model.article.ArticleConstant.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@ExtendWith(SpringExtension.class) +class MemberServiceTest { + private NickName nickName; + private Email email; + private Member member; + + @InjectMocks + private MemberService memberService; + + @Mock + private MemberRepository memberRepository; + + @BeforeEach + void setUp() { + nickName = NickName.of(NICKNAME); + email = Email.of(EMAIL); + member = Member.MemberBuilder.aMember() + .email(EMAIL) + .name(NAME) + .nickName(NICKNAME) + .password(PASSWORD) + .profile(IMAGE_URL) + .build(); + } + + @Test + public void 존재하는_회원을_검색하는_경우_테스트() { + // given + given(memberRepository.findByEmail(email)).willReturn(Optional.of(member)); + + // then + assertThat(memberService.findMemberByEmail(EMAIL)).isEqualTo(member); + } + + @Test + public void 존재하지_않는_회원을_검색하는_경우_테스트() { + // given + given(memberRepository.findByEmail(email)).willReturn(Optional.empty()); + + // then + assertThrows(MemberNotFoundException.class, () -> memberService.findMemberByEmail(EMAIL)); + } + + @Test + public void 회원가입_성공_테스트() { + // given + MemberSignUpRequest request = getMemberSignUpRequest(); + Member member = Deencapsulation.invoke(MemberAssembler.class, "toEntity", request); + + given(memberRepository.existsByNickNameOrEmail(nickName, email)).willReturn(false); + given(memberRepository.save(member)).willReturn(member); + + // when + memberService.save(request); + + // then + verify(memberRepository, times(1)).save(member); + } + + @Test + public void 존재하는_이메일로_가입하는_경우_테스트() { + // given + MemberSignUpRequest request = getMemberSignUpRequest(); + + given(memberRepository.existsByNickNameOrEmail(nickName, email)).willReturn(true); + + // then + assertThrows(MemberSaveException.class, () -> memberService.save(request)); + } + + private MemberSignUpRequest getMemberSignUpRequest() { + MemberSignUpRequest request = new MemberSignUpRequest(); + request.setEmail(EMAIL); + request.setName(NAME); + request.setNickName(NICKNAME); + request.setPassword(PASSWORD); + request.setProfile(IMAGE_URL); + + return request; + } +} \ No newline at end of file