DTO(Data Transfer Object)는 계층간 데이터 교환을 위한 객체(Java Beans)이다.
DB에서 데이터를 얻어 Service나 Controller 등으터 보낼 때 사용하는 객체를 말한다.
package com.rptp.rptpSpringBoot.model;
public class MemberDTO {
private long id;
private String name;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
실제로 DB에 접근하는 객체이다.
Persistence Layer(DB에 data를 CRUD하는 계층)이다.
Service와 DB를 연결하는 고리의 역할을 한다.
후에 repository 변동 용이성을 위해서 interface를 제작한다.
package com.rptp.rptpSpringBoot.repository;
import com.rptp.rptpSpringBoot.model.MemberDTO;
import java.util.List;
import java.util.Optional;
public interface MemberRepository {
MemberDTO save(MemberDTO memberDTO);
Optional<MemberDTO> findById(Long id);
Optional<MemberDTO> findByName(String name);
List<MemberDTO> findAll();
}
package com.rptp.rptpSpringBoot.repository.impliment;
import com.rptp.rptpSpringBoot.model.MemberDTO;
import com.rptp.rptpSpringBoot.repository.MemberRepository;
import java.util.*;
public class MemoryMemberRepository implements MemberRepository {
private static Map<Long, MemberDTO> store = new HashMap<>();
private static long sequence = 0L;
@Override
public MemberDTO save(MemberDTO memberDTO) {
memberDTO.setId(++sequence);
store.put(memberDTO.getId(),memberDTO);
return memberDTO;
}
@Override
public Optional<MemberDTO> findById(Long id) {
return Optional.ofNullable(store.get(id));
}
@Override
public Optional<MemberDTO> findByName(String name) {
return store.values().stream()
.filter(memberDTO -> memberDTO.getName().equals(name))
.findAny();
}
@Override
public List<MemberDTO> findAll() {
return new ArrayList<>(store.values());
}
}
개발한 기능을 실행해서 테스트 할 때 자바의 main 메서드를 통해서 실행하거나, 웹 애플리케이션의 컨트롤러를 통해서 해당 기능을 실행한다.
이러한 방법은 준비하고 실행하는데 오래 걸리고, 반복 실행하기어렵고 여러 테스트를 한번에 실행하기 어렵다는 단점이 있다.
자바는 JUnit이라는 프레임워크로 테스트를 실행해서 이러한 문제를 해결한다.
package com.rptp.rptpSpringBoot.repository.impliment;
import com.rptp.rptpSpringBoot.model.MemberDTO;
import com.rptp.rptpSpringBoot.repository.MemberRepository;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class MemoryMemberRepositoryTest {
MemberRepository repository = new MemoryMemberRepository();
@Test
public void save() {
MemberDTO memberDTO = new MemberDTO();
memberDTO.setName("spring");
repository.save(memberDTO);
MemberDTO result = repository.findById(memberDTO.getId()).get();
Assertions.assertEquals(memberDTO, null);
}
}
junit이 테스트를 시도한다
두 매개변수를 비교하여 같으면 테스트 통과, 다르면 아래와 같이 애러를 호출한다.
Assertions.assertEquals(memberDTO, result);
같으면 위와 같이 tests passed가 뜬다.
package com.rptp.rptpSpringBoot.repository.impliment;
import com.rptp.rptpSpringBoot.model.MemberDTO;
import com.rptp.rptpSpringBoot.repository.MemberRepository;
import org.assertj.core.api.Assertions;
//import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class MemoryMemberRepositoryTest {
MemberRepository repository = new MemoryMemberRepository();
@Test
public void save() {
MemberDTO memberDTO = new MemberDTO();
memberDTO.setName("spring");
repository.save(memberDTO);
MemberDTO result = repository.findById(memberDTO.getId()).get();
Assertions.assertThat(memberDTO).isEqualTo(result);
}
}
org.junit.jupiter.api.Assertions 대신 org.assertj.core.api.Assertions를 import받아 위와 같이 사용할 수 있다.
class MemoryMemberRepositoryTest {
MemberRepository repository = new MemoryMemberRepository();
/*
@AfterEach
public void afterEach() {
//중복 방지를 위하여 각 테스트 종료시 초기화 시켜줘야함
}
*/
@Test
public void save() {
MemberDTO memberDTO = new MemberDTO();
memberDTO.setName("spring");
repository.save(memberDTO);
MemberDTO result = repository.findById(memberDTO.getId()).get();
// Assertions.assertEquals(memberDTO, result);
Assertions.assertThat(memberDTO).isEqualTo(result);
}
@Test
public void findByName() {
MemberDTO member1 = new MemberDTO();
member1.setName("spring1");
repository.save(member1);
MemberDTO member2 = new MemberDTO();
member2.setName("spring2");
repository.save(member2);
MemberDTO result = repository.findByName("spring1").get();
Assertions.assertThat(result).isEqualTo(member1);
}
@Test
public void findAll(){
MemberDTO member1 = new MemberDTO();
member1.setName("spring1");
repository.save(member1);
MemberDTO member2 = new MemberDTO();
member2.setName("spring2");
repository.save(member2);
List<MemberDTO> result = repository.findAll();
Assertions.assertThat(result.size()).isEqualTo(2);
}
}
findByName()에서 에러가 날 것이다.
테스트 경우는 save,findByName,findAll 3개 인데, 이들이 선언 순서대로 테스트 하는 것이 아니다. 그래서 findAll이 먼저 실행되고, findByName이 실행되면, finaAll에서 spring1의 이름을 가지는 객체를 생성해서 findByName에서 다른 값으로 인식할 수 있는 것이다.
public void deleteAll() {
store.clear();
}
해당 메서드를 추가한다.
class MemoryMemberRepositoryTest {
MemoryMemberRepository repository = new MemoryMemberRepository();
@AfterEach
public void afterEach() {
repository.deleteAll();
}
repository를 MemoryMemberRepository로 변경하고, afterEach를 추가한다.
각 테스트가 끝날 때마다 실행하는 메서드에 붙임.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/lecture/49581?tab=curriculum
DTO, DAO, Entity class의 차이 https://gmlwjd9405.github.io/2018/12/25/difference-dao-dto-entity.html