fragile and resilient

Spring 7

[JPA] SimpleJpaRepository의 EntityManager는 어디서 생성될까?

JPA를 사용하면 보통 아래와 같이 선언해서 Repository를 사용합니다. interface JpaTestRepository extends JpaRepository, TestRepository {}여기서 JpaRepository 의 구현체인 SimpleJpaRepository 를 살펴보겠습니다. 데이터를 저장할 때 사용하는 save 메서드를 기준으로 보겠습니다.로직을 보니 entityInformation.isNew를 확인하고 true이면 em.persist(entity)를 실행하고, false이면 em.merge(entity)를 실행합니다. (이 로직에 대한 부분은 다른 포스팅에서 다루겠습니다.) 여기서 em을 통해 로직을 수행하는 것을 보니 EntityManager가 굉장히 중요한 역할을 하는 것으..

Spring 2024.02.24

[Spring] @Transactional을 통해 어떻게 트랜잭션이 보장될까?

스프링 기반 프로젝트에서 매우 익숙하게 보실 수 있는 코드일 텐데요. 스프링에서는 @Transactional 만 붙여주면 메서드 로직의 트랜잭션이 보장됩니다. 디버그를 실행하여 JpaRepository를 상속한 MemberRepository 를 살펴보면 프록시라는 것을 알 수 있습니다. 적용된 어드바이스들을 살펴보면 TransactionInterceptor 가 눈에 띕니다. TransactionInterceptor.invoke를 보면 TransactionAspectSupport.invokeWithinTransaction를 호출하고 있는 것을 알 수 있는데요. 이 메서드가 핵심 로직입니다. 중요한 몇 가지 부분만 보겠습니다.341번 라인의 getTransactionAttribute 메서드를 타고 들어가보면..

Spring 2024.02.21

[Spring, AOP] 테스트 격리를 위한 MockRestServiceServer 초기화

모아모아 프로젝트에서 외부 API와 연동된 테스트를 진행하면서 겪었던 이슈에 대해 정리해 보고자 합니다. 문제 상황 이번 스프린트에서 슬랙 알림을 도입하기로 하여 알림 로직을 구현하였는데요. 기능을 구현하는 데에는 문제가 없었지만, 알림 기능 테스트를 진행하면서 해당 오류를 마주쳤습니다. 오류는 MockRestServiceServer에서 발생하고 있었는데요. 내용을 살펴보면 예상되지 않은 추가 요청이라는 문구를 확인할 수 있었습니다. 본격적으로 문제를 살펴보기 전에 간단하게 프로젝트 로직에 대해 설명해 드리겠습니다. 프로젝트에서는 외부 API와 통신하며 동작하는 기능(Github OAuth, Slack Alarm)이 있는데요. 해당 작업은 RestTemplate를 사용해서 통신하고 있습니다. (RestT..

Spring 2022.10.11

[Spring] 테스트 시간 최적화 (feat.Context Caching)

기능 구현이 늘어나면서 테스트 코드 또한 많아졌는데요. 그에 따라 필연적으로 테스트를 돌리는 시간이 점점 늘어나게 되고, 피드백을 받는 시간이 딜레이됐습니다. 전체 테스트를 돌리는 시간이 꽤 걸리다 보니, 개발을 진행하다가 흐름이 끊기는 것 같은 느낌이 들 때도 있었습니다. 만약 각각의 테스트마다 새로운 스프링 컨텍스트를 띄우면 어떨까요? 매번 새로운 컨텍스트를 띄우기 때문에 테스트를 돌리는 시간이 매우 오래 걸릴 것입니다. 따라서 스프링에서는 Context Caching이라는 것을 제공하는 데요. 스프링은 테스트가 사용하는 컨택스트를 캐싱해서 여러 테스트에서 하나의 컨텍스트를 공유할 수 있는 방법을 제공합니다. 동일한 컨텍스트 구성을 갖는 테스트끼리는 같은 컨텍스트를 공유하는 것입니다. 테스트용 컨텍스..

Spring 2022.08.15

[Spring] Pageable 커스텀 예외 처리(feat. @PageableDefault)

Pageable을 사용해 Pagination을 하는 과정에서, 요구 사항에 맞추어 예외를 처리해야 하는 경험을 했습니다. 저희 팀의 요구 사항은 아래와 같습니다. 요구 사항 page, size에 값이 모두 없을 경우, default로 page = 0, size = 5를 설정한다. size에 0이 들어오거나 page, size에 문자열, 음수가 들어올 경우 400 에러를 응답한다. Pageable을 사용하면서, 위 요구 사항에 맞추어 구현한 경험에 대해 공유하고자 합니다. 1) Pageable page, size Default 값 지정 @RestController public class StudyController { //... @GetMapping("/api/studies") public Response..

Spring 2022.07.05

[Spring] DispatcherServlet 동작 과정과 Special Bean Types

Spring MVC는 front controller pattern으로 설계되어 있는데, 여기서 front controller가 바로 DispatcherServlet입니다. DispatcherServlet은 요청에 필요한 공통된 알고리즘을 제공하고, 실제 동작은 각각의 적절한 컴포넌트에게 위임합니다. 또한 다른 Servlet과 마찬가지로 Java configuration이나 web.xml에 선언하여 매핑되어야 하는데요. DispatcherServlet은 Spring configuration을 통해 request mapping, view resolution, exception handling에 필요한 컴포넌트를 찾습니다. DispatcherServlet은 설정을 위해 WebApplicationContext을..

Spring 2022.07.03

[Test] 컨트롤러 테스트해야 할까? (feat. 테스트에 대한 혼동)

문제 상황 테스트 코드를 작성하는 과정에서 테스트 종류에 대한 혼동과 인수 테스트, 컨트롤러 테스트에 대한 차이에 대한 의문이 들었습니다. 해당 고민에 대한 개인적인 생각을 정리해보고자 합니다. 우선 테스트 종류에 대해 알아봅시다. 테스트 종류 단위 테스트 구현한 부분의 단위를 검증 (하나의 클래스 또는 하나의 메서드) 통합 테스트 각 단위들이 유기적으로 잘 동작되는지 검증 E2E 테스트 요구사항을 만족하는지 검증 인수 테스트 (Acceptance Test) API 접점을 검증하는 E2E 테스트 사용자 스토리를 검증하는 기능 테스트 타겟은 프론트엔드 개발자 혹은 API 활용하는 사람 API의 Request와 Response 정보 이외의 내부 정보를 최대한 가리는 블랙 박스 형식의 테스트 각각의 테스트는 ..

Spring 2022.05.25