다음으로 멤버십을 등록할 테스트를 작성해 보았다.
@Test
void 멤버십등록() {
//given
Membership member = Membership.builder()
.userId("userA")
.membershipName("네이버")
.point(10000)
.build();
//when
// 실제로는 dto로 받아와서 엔티티에 값을 넣어준다. 하지만 테스트 코드 작성이므로 바로 엔티티에 저장후 값을 확인한다.
Membership result = membershipRepository.save(member);
//then
assertThat(result.getId()).isNotNull();
assertThat(result.getUserId()).isEqualTo(member.getUserId());
assertThat(result.getMembershipName()).isEqualTo(member.getMembershipName());
assertThat(result.getPoint()).isEqualTo(member.getPoint());
}
Membership 엔티티 클래스에 해당 컬럼들이 없기 때문에 컴파일 오류가 난다. 컬럼을 생성하고 다시 테스트를 돌려보자
public class Membership {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // id 자동증가 생성
private Long id;
@Column
@NotNull
private String userId;
@Column
@NotNull
private String membershipName;
@Column
private int point;
@CreationTimestamp
@Column(nullable = false, length = 20, updatable = false)
private LocalDateTime createdAt;
@UpdateTimestamp
@Column(length = 20)
private LocalDateTime updatedAt;
}
이후 테스트를 다시 돌려보면 성공하는 것을 볼 수 있다.
리팩토링 단계로 멤버십타입을 enum형식으로 바꾸면 관리하기 좋을 것 같다.
@Test
void 멤버십등록() {
//given
Membership member = Membership.builder()
.userId("userA")
.membershipName(MembershipType.NAVER)
.point(10000)
.build();
//when
// 실제로는 dto로 받아와서 엔티티에 값을 넣어준다. 하지만 테스트 코드 작성이므로 바로 엔티티에 저장후 값을 확인한다.
Membership result = membershipRepository.save(member);
//then
assertThat(result.getId()).isNotNull();
assertThat(result.getUserId()).isEqualTo(member.getUserId());
assertThat(result.getMembershipName()).isEqualTo(member.getMembershipName());
assertThat(result.getPoint()).isEqualTo(member.getPoint());
}
enum형식이 없으므로 컴파일 오류가 난다. 매우 잘한 것이다.
테스트 코드를 먼저 변경하고 그 이후에 프로덕트 코드를 변경하는 단계를 잘 생각해서 해보자.
컴파일 오류를 확인 했으니, MembershipType enum클래스를 만들어보자.
@Getter
@RequiredArgsConstructor
public enum MembershipType {
NAVER("네이버"),
LINE("라인"),
KAKAO("카카오"),
;
private final String companyName;
}
테스트를 돌려보면 아직 컴파일 오류가 난다.
Membership 클래스의 membershipType을 String 타입으로 해놨기 때문에 오류가 난다.
String을 MembershipType타입으로 변경하고 다시 테스트를 돌려보자
성공하였다!!
다음으로는 어떤 사용자가 중복으로 같은 멤버십을 등록할 시 중복이 안되게 등록하지 못하게 하는 것이다.
일단 레파지토리에서 userId와 MembershipType으로 해당 엔티티를 찾는 테스트 코드부터 작성해보자.(그래야 서비스 부분에서 중복 검사시 필요한 데이터를 찾을 수 있기 때문이다.){
@Test
void 사용자가이미등록한멤버십일때_중복검사(){
//given
Membership member = Membership.builder()
.userId("userA")
.membershipName(MembershipType.NAVER)
.point(10000)
.build();
//when
Membership result = membershipRepository.save(member);
Membership findresult = membershipRepository.findByUserIdAndMembershipType("userA", MembershipType.NAVER);
//then
assertThat(findresult.getId()).isNotNull();
assertThat(findresult.getUserId()).isEqualTo(result.getUserId());
assertThat(findresult.getMembershipName()).isEqualTo(result.getMembershipName());
assertThat(findresult.getPoint()).isEqualTo(result.getPoint());
}
레파지토리에 findByUserIdAndMembershipTyp이 존재하지 않아 컴파일 오류가 난다.
레파지토리에 추가해주자.
public interface MembershipRepository extends JpaRepository<Membership, Long> {
Membership findByUserIdAndMembershipType(String userId, MembershipType membershipType);
}
다시 실행해보면 정상적으로 findByUserIdAndMembershipType이 잘 작동 되며 테스트에 성공하는 것을 볼 수 있다.
야호!
다음으로 Service부분을 테스트 할 차례이다.
처음으로 멤버십 등록을 할 때 중복 검사를 실행시켜 중복이 있을 시 생성을 하지 않는 테스트 코드를 작성해본다.
@Test
void 멤버십서비스에서중복검사(){
//given
//제일 먼저 멤버십이 있다는 가정을 한다.
Membership member = Membership.builder()
.userId("userA")
.membershipType(MembershipType.NAVER)
.point(10000)
.build();
Membership userA = membershipRepository.save(member);
//when
String userId = "userA";
MembershipType membershipType = MembershipType.NAVER;
Integer point = 10000;
Membership result = memberService.create(userId, membershipType, point);
//then
assertThat(result.getId()).isNotNull();
assertThat(result.getUserId()).isEqualTo(userA.getUserId());
assertThat(result.getMembershipType()).isEqualTo(userA.getMembershipType());
}
제일 처음 해당 멤버십을 가지고 있으면 있다고 말해준뒤 등록할 멤버십이 원래 있는 멤버십이 같은지 테스트하는 코드를 작성했다.
같은지 테스트를 한 후 리팩토링을 할 것이다.
제일 먼저 memberService가 없기 때문에 프로덕트 코드에 MemberService를 추가해준 후, create메서드를 작성한다.
public Membership create(String userId, MembershipType membershipType, Integer point) {
Membership result = membershipRepository.findByUserIdAndMembershipType(userId, membershipType);
if(result != null) {
System.out.println("이미 등록된 회원멤버십입니다.");
Membership member = Membership.builder()
.userId(userId)
.membershipType(membershipType)
.point(point)
.build();
Membership makeMembership = membershipRepository.save(member);
return makeMembership;
} else {
Membership member = Membership.builder()
.userId(userId)
.membershipType(membershipType)
.point(point)
.build();
Membership makeMembership2 = membershipRepository.save(member);
return makeMembership2;
}
}
현재 create 메서드는 테스트 확인을 위해 작성하였다. 테스트에 성공하면 리팩토링을 통해 다시 재작성한다.
테스트를 돌려보면 result != null가 참이기 때문에
"이미 등록된 회원멤버십입니다."라는 출력을 하며
id값이 2인 엔티티가 생성된다.
MembershipService에서 컨트롤러로 반환하는 객체는 Membership 엔티티이다. 엔티티를 반환하는 것 보다는 DTO를 반환하는 것이 바람직하므로 DTO를 반환하도록 리팩토링하도록 하자.
public class MembershipDto {
private Long id;
private String userId;
private MembershipType membershipType;
private int point;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
public Membership toEntity(){
Membership membership = Membership.builder()
.id(id)
.userId(userId)
.membershipType(membershipType)
.point(point)
.createdAt(createdAt)
.updatedAt(updatedAt)
.build();
return membership;
}
}
Membership 엔티티 클래스에도 toDto()메서드를 작성하여 만들어둔다.(빌더 사용)
public Membership create(String userId, MembershipType membershipType, Integer point /*나중에 MembershipDto로 변경*/) {
Membership result = membershipRepository.findByUserIdAndMembershipType(userId, membershipType);
if(result != null) {
System.out.println("이미 등록된 회원멤버십입니다.");
return null;
} else {
// MembershipDto로 받은 데이터 toEntity()메서드를 사용하여 엔티티로 변경
Membership member = Membership.builder()
.userId(userId)
.membershipType(membershipType)
.point(point)
.build();
Membership makeMembership2 = membershipRepository.save(member);
return makeMembership2;
}
}
현재 테스트 코드 작성을 기반으로 아직 컨트롤러 부분의 프로덕트 코드가 작성되지 않았기 때문에 서비스 부분의 프로덕트 코드 중, 리팩토리해야 할 부분을 주석처리 함으로써 쉽게 수정할 수 있게 만든다.
컨트롤러 부분의 테스트는 MockMvc를 사용하여 진행해야 하는데 아직 배우지 않아 요번 공부에서 컨트롤러 테스트는 뺐다.