
살짝 서두른 Spring 기반 테스트 코드 - 인프런 워밍업 클럽 3기 백엔드 코드✨
인프런 워밍업 클럽 3기 백엔드 코드 발자국 1주차
인프런 워밍업 클럽 3기 백엔드 코드 발자국 2주차
인프런 워밍업 클럽 3기 백엔드 코드 발자국 3주차
🎼 알레그레토 : 조금 빠르게
3주 차부터는 미션과 발자국을 조금 서둘러 진행할 예정이다.
앞서 언급했듯이, 이번 주부터 항해 플러스가 시작되어 최대한 진도를 빠르게 빼보려고 한다.
현재 날짜(3월 17일) 기준으로 Day 16 미션과 3주 차 발자국을 작성 중이며,
이번 주 안에 Day 18 미션과 4주 차 발자국도 작성을 완료하는 것이 목표이다.
(가능할지는 모르겠지만 ㅎㅎ)
조금 급하게 진행하는 감이 있어 개인적으로 많이 아쉽다.
워밍업 클럽에만 온전히 집중할 수 있었다면 더 많은 성장을 할 수 있었을 텐데 말이다...
하지만, 후회는 하지 않는다. 다음 기수의 존재는 우빈님만 아시겠지만, 다음에 또 없을 수도 있는 기회를 놓치고 싶지 않았기 때문이다. 👍
나는 위의 이미지처럼 Trello를 활용해 인프런 워밍업 클럽에 참여하고 있다.
미션 제출 날짜가 일정하지 않다 보니, 제출 하루 전에 노티를 받도록 설정해 두고 유용하게 사용 중이다. 🙃
💡 자기만의 언어로 키워드 정리하기
섹션 6. Spring & JPA 기반 테스트
Layered Architecture
레이어드 아키텍처의 단점 : 기술에 대한 강결합이 심하다는 단점이 존재
Hexagonal Architecture
도메인 모델은 외부의 것들을 아예 모른다.
도메인 모델 중심 (멀티 모듈 및 시스템이 커진다면..)
단위테스트 vs. 통합테스트
단위테스트 만으로는 커버하기 어려운 영역이 존재 (여러 모듈 및 여러 객체가 협력하기 때문에)
통합테스트란?
여러 모듈이 협력하는 기능을 통합적으로 검증하는 테스트
단위 테스트만으로는 기능 전체의 신뢰성을 보장할 수 없다.
IoC, DI, AOP
ORM, 패러다임의 불일치, Hibernate
Spring Data JPA
QueryDSL
@SpringBootTest vs @DataJpaTest
@DataJpaTest는 @SpringBootTest보다 가볍다.
@DataJpaTest보다는 @SpringBootTest를 더 선호
@DataJpaTest는 @Transactional이 있어 롤백이 된다.
@SpringBootTest는 클렌징을 해주어야 한다.
@SpringBootTest vs @WebMvcTest
@SpringBootTest는 E2E 테스트, 즉 통합테스트 시 사용하는 어노테이션이다.
@WebMvcTest는 Presentation Layer에 대한 단독 테스트시 사용하는 어노테이션이다.
다른 레이어들은 mocking을 통해 동작을 제어한다.
@Transactional(readOnly = true)
테스트에서 사용 시, 롤백 되는 것에 유의 해야 한다.
트랜잭션 경계 설정을 해야한다.
엔드포인트를 잘 설계해야 한다.
Optimistic Lock, Pessimistic Lock
낙관적 락 : 데이터 충돌이 자주 발생하지 않을 것이라 낙관적으로 가정하고, 트랜잭션을 진행하는 방식
데이터를 읽을 때는 락을 걸지 않고, 데이터를 업데이트 시 버전 비교하여 충돌 여부 판단
성능 저하를 최소화, 동시성을 높이는 데 유리
비관적 락 : 데이터 충돌이 자주 발생할 것이라 비관적으로 가정하고, 트랜잭션이 데이터를 사용할 때 미리 잠금을 거는 방식
데이터 일관성을 유지하는 데 초점
트랜잭션이 완료될 때까지 다른 트랜잭션이 데이터를 수정할 수 없음
데드락 발생 가능
CQRS
명령 조회 책임 분리 : Command Query Responsibility Segregation
읽기(조회)와 쓰기(명령)의 책임을 분리하는 소프트웨어 아키텍처 패턴
장점
성능 최적화
확장성 증가
데이터 모델 최적화
비지니스 로직의 명확한 분리
단점
복잡성 증가
데이터 동기화 문제
트랜잭션 관리 어려움
@RestControllerAdvice, @ExceptionHandler
@RestControllerAdvice : ControllerAdvice의 기능을 하는데 JSON으로 응답을 해주는 Advice
커스텀 예외를 던지고 @RestControllerAdvice의 @ExceptionHandler에서 예외를 처리할 수 있다.
Spring bean validation
@NotNull, @NotEmpty, @NotBlank
도메인 요구사항에서 나오는 validation과 책임 분리해야한다.
Controller 단에서는 최소한의 validation을 통한 검증이 이루어져야 한다.
@WebMvcTest
ObjectMapper
Jackson 라이브러리에서 제공하는 클래스로, Java 객체와 JSON 간의 변환을 담당하는 역할
직렬화, 역직렬화를 수행
Mock, Mockito, @MockBean
Mock : 실제 객체 없이 동작을 모방하여 단위 테스트를 수행하는 가짜 객체
Mockito : Java에서 Mock 객체를 쉽게 생성하고 관리할 수 있는 라이브러리
@MockBean : Spring 컨텍스트에 Mock 객체를 등록하여 실제 빈을 대체
@Mock : 순수한 자바에서 Spring 컨텍스트가 필요하지 않을 때 사용
@MockBean : Spring 컨텍스트에서 특정 빈을 Mocking 하고 싶을 때 사용
👨🏻💻 미션 회고
[미션 Day 11]
[미션 PR]
#6
스터디 카페 이용권 선택 시스템 단위 테스트 작성
미션 조건은 다음과 같다.
✔각 프로젝트 모두 강의 중에 작성한 tobe 패키지 코드를 기준으로 함 (lesson 6-4 가 가장 마지막 버전)
✔3개 이상의 서로 다른 클래스 & 총 7개 이상의 테스트 작성 ➡ 단, 같은 인터페이스를 구현하고 있는 구현체들은 1개 클래스로 간주한다.
✔무엇을 테스트하고자 했는지를 잘 나타낸 @DisplayName 작성하기
✔BDD(given/when/then) 스타일 따르기 (주석으로 표기)
가장 작은 단위의 메서드 부터 단위 테스트를 작성하면서,
테스트 커버리지를 높이기 위해, 모든 주요 로직에 대한 단위테스트를 작성하고자 했다.
단위테스트를 작성하면서 강의에서도 강조한 내용 중에 하나인 @DisplayName
을 잘 작성하기 위해 많이 고민했다.
'권'이라는 Pass의 의미를 '패스'로 통일하여 일관성있게 작성하였다.
읽는 사람으로 하여금 뇌 메모리를 적게 쓰게 하기 위해
@DisplayName
도 최대한 추상화해서 작성하려고 노력했다.테스트의 현상을 중점적으로 작성하지 않으려고 하였다.
하지만, 사용자 입력을 받는 클래스인 InputHandler의 단위테스트를 작성하는 과정에서 어려움이 있었다.
InputHandler 내부에서 static으로 선언되어 있어 mocking도 하기 어려웠다.
public class InputHandler {
private static final Scanner SCANNER = new Scanner(System.in);
}
프로덕션 코드를 수정하지 않는다는 요구사항을 지키면서는 테스트가 어려웠다.
만약 프로덕션 코드를 수정한다면 테스트가 가능해질 것이다.
👆 Scanner를 외부세계로 분리하면 테스트가 가능할 것 같다.
✌ InputHandler 상위의 인터페이스를 생성 후, 테스트 전용 support 성격의 구현체를 만들어서 테스트가 가능할 것 같다.
미션 제출 후, 차후에 프로덕션 코드를 수정해서 테스트를 작성 해볼 예정이다.
🏃 돌아보며..
Day 11 미션은 제출이 끝이 아니라, 중간점검 라이브에 이어 마지막 라이브에서 코드 리뷰 단계가 남아있다.
중간 점검 때 세심한 코드 리뷰를 받고 수정하면서 많은 성장을 했기에 이번에도 신청하지 않을 이유가 없었다.
다른 러너 분들도 꼭 받아봤으면 한다. 😊
아직까지 혼자 신청해서 뻘줌해서가 아니라... 진짜 좋은 기회이자 경험이다... 🤣
코드 리뷰 대상자로 뽑히길 기대하며.. 마지막 4주차도 화이팅 💪
[출처]
댓글을 작성해보세요.