Soft Delete기능을 만들고 Test코드까지 만들어 확인을 하였다.
@DataJpaTest를 통해 Test를 진행하였다.
DB는 h2DB를 사용했다.
server:
servlet:
encoding:
force-response: true
spring:
jpa:
hibernate:
ddl-auto: update
show-sql: true
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_DELAY=-1
username: sa
password:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
h2:
console:
enabled: true
logging:
level:
org:
hibernate:
SQL: DEBUG
@DataJpaTest
class PostRepositoryTest {
@Autowired
PostRepository postRepository;
@Autowired
UserRepository userRepository;
@Test
@DisplayName("soft delete 테스트")
void post_softDelete_success() {
//Post에 적용할 user를 생성
User user = User.builder()
.userName("userName")
.password("password")
.role(UserRole.ROLE_USER)
.build();
//user 저장
User saveUser = userRepository.save(user);
//Post 생성
Post post = Post.builder()
.title("test")
.body("softDeleteTest")
.user(saveUser)
.build();
//글쓰기
Post savePost = postRepository.save(post);
//게시글 확인
assertEquals(postRepository.count(),1);
assertEquals(savePost.isSoftDeleted(),false);
//게시글 삭제
savePost.deleteSoftly(LocalDateTime.now());
//게시글 삭제 확인
assertEquals(postRepository.count(),0);
assertEquals(savePost.isSoftDeleted(),true);
}
}
그런데 의문이 생겼다.
진짜 잘 되는거 맞아??
Soft Delete라면 물리적 삭제가 아닌 논리적 삭제가 되어야 하니까, 실제 DB의 값은 존재해야한다.
하지만 위의 로직으로는 DB의 값이 존재하는지 안하는지 확인 할 수가 없다.
Post에 @Where조건으로 쿼리조회시 deltedAt = null일경우만 조회되게 설정했기 때문이다.
그렇기 때문에 게시글을 삭제하고 DB를 Conunt했을시 0이 나온것이다.
원하는것은 논리적 삭제가 구현되었는지 DB에서 직접 확인하고 싶었다.
Test로 DB를 조회하는 방법은 없을까??
DB를 직접 확인하기위해 Local DB를 이용할 것이다.
@SpringBootTest
를 통해 통합테스트를 진행하고
@ActiveProfiles("test")
로 application-test.yml파일을 적용시켰다.
DB password는 환경변수로 주입시켰다.
server:
servlet:
encoding:
force-response: true
spring:
jpa:
hibernate:
ddl-auto: create
show-sql: true
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
자 이제 세팅은 끝났다 Test를 진행해 보자.
@SpringBootTest
@ActiveProfiles("test") // local db에 row가 있는지 직접 확인 하고 싶을 때 쓴다
class PostServiceWithSpringTest {
@Autowired
PostRepository postRepository;
@Autowired
UserRepository userRepository;
User user;
Post post;
@BeforeEach
void setUp() {
user = User.builder()
.userName("userName")
.password("password")
.role(UserRole.ROLE_USER)
.build();
post = Post.builder()
.title("test")
.body("softDeleteTest")
.user(null)
.build();
}
@Test
@DisplayName("soft delete 테스트")
void post_softDelete_success() {
//user 저장
User saveUser = userRepository.save(user);
//Post 생성
post.setUser(saveUser);
//글쓰기
Post savePost = postRepository.save(post);
//게시글 확인
assertEquals(postRepository.count(),1);
assertEquals(savePost.isSoftDeleted(),false);
assertNull(savePost.getDeletedAt());
//게시글 삭제
savePost.deleteSoftly(LocalDateTime.now());
//게시글 삭제 확인
assertEquals(postRepository.count(),0);
assertEquals(savePost.isSoftDeleted(),true);
assertNotNull(savePost.getDeletedAt()); //삭제가 되었다는 뜻
}
}
위와같이 Test를 작성하고 실행해 보았다.
그런데 테스트가 통과하지 못했다.
원인은 soft delete가 실행되지 않았던 것이다...
왜그런걸까? 생각해보니 @Transactional 어노테이션을 빼먹어서 그런것을 깨달았다!
그래서 바로 적용시켜보았다.
@SpringBootTest
@Transactional //Test에 Transactional을 붙이면 끝나면 롤백된다.?
@ActiveProfiles("test") // local db에 row가 있는지 직접 확인 하고 싶을 때 쓴다
class PostServiceWithSpringTest {
테스트가 통과되었다.
그런데 왜 DB에는 적용이 안된걸까??
Soft delete라면 post는 존재하지만 논리적으로만 삭제되어야 할텐데??
Test는 @RollBack 어노테이션이 따로 존재한다.
일반적으로 Test code는 DB에 반영하지 않고 로직 진행후
다시 rollback 하는 것이 true 로 되어있는대 이게 싫다면
@Rollback(value false) 옵션 적용하면 된다!
@SpringBootTest
@Transactional //Test에 Transactional을 붙이면 끝나면 롤백된다.?
@Rollback(value = false)
@ActiveProfiles("test") // local db에 row가 있는지 직접 확인 하고 싶을 때 쓴다
@Slf4j
class PostServiceWithSpringTest {
@Autowired
PostRepository postRepository;
@Autowired
UserRepository userRepository;
User user;
Post post;
Like likes;
@BeforeEach
void setUp() {
// postRepository.deleteAll();
// userRepository.deleteAll();
user = User.builder()
.userName("userName")
.password("password")
.role(UserRole.ROLE_USER)
.build();
post = Post.builder()
.title("test")
.body("softDeleteTest")
.user(null)
.build();
}
@Test
@DisplayName("soft delete 테스트")
void post_softDelete_success() {
//user 저장
User saveUser = userRepository.save(user);
//Post 생성
post.setUser(saveUser);
//글쓰기
Post savePost = postRepository.save(post);
//게시글 확인
log.info("\n" + "count" + "\n");
assertEquals(postRepository.count(),1);
assertEquals(savePost.isSoftDeleted(),false);
assertNull(savePost.getDeletedAt());
//게시글 삭제
log.info("\n" + "deleteSoftly" + "\n");
savePost.deleteSoftly(LocalDateTime.now());
// postRepository.save(savePost);
//게시글 삭제 확인
log.info("\n" + "count 2" + "\n");
assertEquals(postRepository.count(),0);
assertEquals(savePost.isSoftDeleted(),true);
assertNotNull(savePost.getDeletedAt()); //삭제가 되었다는 뜻
}
}
Soft Delete의 테스트방식을 의심하는것부터 시작해서
Soft Delete를 LocalDB에 적용해보고 실제로 확인하는 작업을 하였다.
그 과정에서 LocalDB에 Test를 연결하는 방법을 알았고,
@Transactional 어노테이션의 동작방식에 대해서 조금은 더 익숙해진것 같다.
하지만 아직 완벽히 이해한것은 아니여서 엔티티 매니저, 영속성컨택스트, 1차캐시, 더티체킹, flush commit
JPARepository에서 제공하는 메서드 동작방식위주로 더 공부를 해봐야겠다.
해결하는데 시간은 좀 걸렸지만, 많이 배울 수 있는 시간이였다!