스프링 통합 테스트
이전에 했던 테스트는 순수한 자바 코드에 대한 테스트이다,
이제는 스프링과 엮어서 테스트를 해보자
Test 클래스의 어노테이션으로 SpringBootTest 선언
그리고, Transactional 도 선언
@SpringBootTest
@Transactional
이제 beforeEach는 지워도 된다!
왜?
@BeforeEach
public void beforeEach() {
memberRepository = new MemoryMemberRepository();
memberService = new MemberService(memberRepository);
}
이 코드는 직접 객체를 생성하지만
이제는? 스프링 컨테이너에서 멤버 리포지토리를 가져와야 한다
테스트는 테스트만 하면 되기 때문에, 다른 곳에서 사용하지 않을 것이다
편하게 @Autowired 를 사용하자
그리고, MemoryMemberRepository가 아닌 MemberRepository를 선언
@Autowired MemberService memberService;
@Autowired MemberRepository memberRepository;
AfterEach 어노테이션까지 삭제하자!
왜?
@AfterEach
public void afterEach() {
memberRepository.clearStore();
}
테스트끼리 메모리 DB의 영향을 끼칠 수 있어서, 저장했던 것을 지워주는 코드인데
@Transational 어노테이션으로 인해 필요 없어짐
- 데이터베이스에는 기본적으로 Transation이라는 개념이 있는데, DB의 데이터에서 커밋을 해줘야, 반영이 된다
- 자동으로 커밋을 하는지 안하는지 에 대한 차이
- 커밋하기 전엔 반영이 안됨
- 이 어노테이션을 사용해서, 테스트 케이스에 달면, 테스트를 실행할 때 Transation을 먼저 실행한다
- DB의 데이터를 insert query한 후, 테스트가 끝나면 롤백한다 → DB의 데이터가 반영이 안되고 지워진다
Example
테스트 실행 전에 Transation을 걸고 DB에 쿼리를 날린다.
그 다음에 테스트가 끝나면, 데이터를 지워버리고 반영을 안한다
→ 다음 테스트를 반복해서 실행할 수 있다
테스트는 테스트 전용 DB를 따로 만들어서 테스트 하던가
로컬 PC의 DB에서 테스트를 하던가 해서 안전하다
@SpringBootTest : 스프링 컨테이너와 테스트를 함께 실행한다
@Transactional : 테스트 케이스에 해당 어노테이션이 있으면 테스트 시작 전에 트랜잭션을 시작한다, 그리고 테스트 완료 후 항상 롤백한다 → DB에 데이터가 남지 않아서, 다음 테스트에 영향을 주지 않는다
Transactional이 서비스에 붙으면 롤백하지 않고 정상적으로 작동, 테스트 케이스에 붙었을 때만 롤백
좋은 테스트 케이스란.. 고민해보자
- 단위로 잘게 쪼갠 테스트
- 스프링 컨테이너 없이 테스트
컨테이너까지 어쩔 수 없게 올려야 하면 설계가 잘못되어있을 확률이 높다
진짜 좋은 테스트는 단위 테스트를 잘 만드는 것…
스프링 JDBC Template
JDBC API에서의 반복 코드를 대부분 제거해준다 !
대신, SQL은 직접 작성해야 한다
JdbcTemplateMemberRepository 클래스 만들기
public class JdbcTemplateMemberRepository implements MemberRepository {
private final JdbcTemplate jdbcTemplate;
public JdbcTemplateMemberRepository(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
}
@Override
public Member save(Member member) {
return null;
}
@Override
public Optional<Member> findById(Long id) {
return Optional.empty();
}
@Override
public Optional<Member> findByName(String name) {
return Optional.empty();
}
@Override
public List<Member> findAll() {
return null;
}
}
일단 JdbcTemplate 생성
💡 생성자가 하나 일 때,
JdbcTemplateMemberRepository의 어노테이션으로 @Autowired를 생략할 수 있다
조회하는 Query 만들기
1. RowMapper를 설정해주자!
private RowMapper<Member> memberRowMapper() {
return (rs, rowNum) -> {
Member member = new Member();
member.setId(rs.getLong("id"));
member.setName(rs.getString("name"));
return member;
};
}
2. 조회 Query를 Optional로 반환하자!
@Override
public Optional<Member> findById(Long id) {
List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper());
return result.stream().findAny();
}
memberRowMapper를 통해서 매핑하고,
리스트로 받아서,
Optional로 반환
저장하는 Query 만들기
@Override
public Member save(Member member) {
SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
jdbcInsert.withTableName("member").usingGeneratedKeyColumns("id");
Map<String, Objects> parametrers = new HashMap<>();
parametrers.put("name", member.getName());
Number key = jdbcInsert.executeAndReturnKey(new MapSqlParameterSource(parametrers));
member.setId(key.longValue());
return member;
}
@참고자료
[인프런] 김영한 - 스프링 입문 강의 (무료)
'개발일지 > Spring' 카테고리의 다른 글
[Spring] 스프링 입문 - AOP (0) | 2023.10.01 |
---|---|
[Spring] 스프링 입문 - JPA (0) | 2023.10.01 |
[Spring] 스프링 입문 - 회원 관리 예제, 웹 MVC 개발 (0) | 2023.09.28 |
[Spring] 스프링 입문 - 스프링 빈과 의존 관계 (1) | 2023.09.28 |
[Server] TCP와 UDP (0) | 2023.09.26 |