블로그
전체 82025. 03. 23.
0
[인프런 워밍업 클럽 백엔드 프로젝트 스터디 3기] 3주차 발자국
4주차 발자국입니다. 공통 예외 처리 및 응답 구조 설계AdminException과 @RestControllerAdvice를 활용한 공통 예외 처리 구현ApiResponse 클래스를 통한 일관된 응답 메시지 제공 Form 및 Table DTO 설계FormElementDTO를 상속받은 다양한 Form 요소 구현 (Text, Date, Select)TableDTO로 서버에서 테이블 구조와 데이터를 내려주는 방식 Interceptor 및 동적 메뉴 구성AdminInterceptor를 활용하여 메뉴 동적 렌더링 구현대메뉴(MenuDTO)와 소메뉴(PageDTO) 구조 설계 및 사이드바 연동 조회 페이지 개발 (연관관계 유무 구분)연관관계 없는 테이블 (e.g., Link, Skill)연관관계 있는 테이블 (e.g., Project-Detail, Experience-Detail)복잡한 구조에 맞춘 TableDTO.from() 사용법 숙지 삽입 및 수정 API 개발@Validated, @NotBlank, @Positive 등을 활용한 Form 유효성 검증연관관계에 따라 다양한 save/update 로직 분기 처리JPA의 더티 체킹을 이해하고, 적절히 save() 호출 생략 뷰 개발 및 템플릿 구조화부트스트랩 템플릿 적용 (BootstrapMade)th:fragment를 활용한 HTML fragment 분리템플릿 관리 편의성 향상Keep(잘한 점)실무에서 vo와 dto의 개념이 혼동되어 쓰이고 있는 경우를 많이 보았는데, 이번 강의를 통해 FormElementDTO와 TableDTO를 도입해, 프론트-백 간 협업에서 구조를 명확히 정의하는 것이 중요하다는 것을 이해했다.Interceptor로 메뉴를 동적으로 설정하고, 뷰에서 자동 렌더링되도록 만든 구조는 앞으로 다양한 관리 페이지에서 재사용 가능한 점에 대한 이해했다.@RestControllerAdvice 기반의 예외 처리로 서비스 전반의 일관성을 유지하는 방식을 이해했다.연관관계에 따른 테이블 구성 방식을 정리하며 도메인 간 설계가 훨씬 명확해짐을 이해했다.Problem(아쉬운 점)리플렉션 사용에 대한 성능 이슈에 대하여 명백한 근거를 잘 모르겠던 부분이 있어서 추가 학습이 필요해보인다.연관관계가 복잡한 엔티티일수록 form → entity 매핑이 반복되며 번거로운 거 같은데 지식이 부족한 거 같다. Try(다음에 시도해볼 점)interceptor 외에 AOP를 활용한 공통 관심사 처리를 구현해보려고 한다.예외 응답에 error code 및 field 정보 추가하여 클라이언트 UX 향상시키면 어떨까 라는 생각이 들었다.내가 다니는 회사에서는 admin화면이 존재하지 않아 익숙하지 않은 부분이 있었는데 학습을 진행한 후에는 서비스를 제공함에 있어서 정말 중요한 요소 중 하나라는 생각이 더더욱 들었다. 관리자 화면과 클라이언트 화면은 어떠한 차이를 가져야하는지 더 실무적으로 경험해보고 싶었다.
백엔드
・
백엔드
・
백엔드프로젝트
・
워밍업클럽3기
2025. 03. 16.
0
[인프런 워밍업 클럽 백엔드 프로젝트 스터디 3기] 2주차 발자국
학습 내용2주차 발자국입니다.1. 데이터베이스 및 리포지토리데이터베이스 초기화: H2 및 MySQL을 활용한 데이터베이스 설정과 application.yml 환경 분리리포지토리 개발: JpaRepository 상속을 통해 기본적인 CRUD 메서드 활용리포지토리 테스트 코드 작성: Mock을 활용한 단위 테스트 (@DataJpaTest, @MockBean)리포지토리 성능 개선: N+1 문제 해결2. 엔티티 및 서비스 개발클래스 생성: 엔티티 정의 (@Entity, @Id, @GeneratedValue)DTO 개발: 엔티티와 분리된 data class 정의로 API 응답 최적화서비스 개발: 비즈니스 로직을 @Service 클래스에서 관리하여 Controller와 역할 분리서비스 테스트 코드 작성: @InjectMocks와 @Mock을 활용한 Mockito 기반 테스트3. 컨트롤러 및 API 개발컨트롤러 개발: @RestController와 @Controller를 활용한 API 및 뷰 렌더링 처리컨트롤러 테스트 코드 작성: MockMvc를 활용하여 API 응답 검증 (@SpringBootTest, @AutoConfigureMockMvc)4. Thymeleaf 기반 UI 개발부트스트랩 템플릿 적용: Start Bootstrap을 활용한 기본 레이아웃 구성템플릿 수정index.html: 주요 콘텐츠 및 네비게이션 구성resume.html: 경력 및 기술 스택 표시projects.html: 프로젝트 목록을 동적으로 표시레이아웃: th:fragment를 활용한 네비게이션 및 푸터 분리5. 인터셉터 개발인터셉터 활용: HandlerInterceptor를 구현하여 요청 전/후 로직 추가주요 기능: 인증/인가 체크, 요청 로깅, 공통 헤더 처리Keep (만족했고, 앞으로도 지속하고 싶은 부분)리포지토리와 서비스의 명확한 역할 분리로 유지보수성이 향상된 점을 느꼈다Mock 테스트를 활용하여 서비스 및 컨트롤러 단위 테스트를 효과적으로 구현했는데, 이전에 워밍업클럽에서 테스트코드를 들어서 그런지 쉽게 이해가 됐다Thymeleaf Fragment 적용으로 중복 코드 제거 및 템플릿 유지보수 능력을 길렀다Problem (아쉬웠던 점)jpa 성능 최적화에 대한 지식이 아직 부족한 거 같아서 김영한 강사님의 강의를 수강해볼 예정Thymeleaf에서 동적 데이터 처리의 한계가 있어 React/Vue 같은 프론트엔드 연계를 고민해야 할텐데 관련하여 지식이 너무 적다 Try (다음에 시도해볼 점)N+1 성능문제 개선 및 QueryDSL을 활용한 복잡한 검색 기능 최적화API 개발 시 OpenAPI(Swagger) 문서 자동화 적용Thymeleaf 대신 React와 연동인터셉터 로직이 복잡해질 경우 AOP를 활용하는 방법도 고려할 필요가 있어보이는데 AOP 구현하는 미니프로젝트 해볼 예정
백엔드
・
코틀린
・
백엔드
・
워밍업클럽3기
2025. 03. 09.
0
[인프런 워밍업 클럽 백엔드 프로젝트 스터디 3기] 1주차 발자국
학습 내용스프링, jpa, 코틀린을 통해 나만의 포토폴리오 등록 사이트를 개발해보는 첫 발자국입니다.실습 전 이론 학습이 강의의 가장 좋은 점이다. 기초적인 지식을 먼저 학습한 다음 실습을 접할 수 있어 지식의 공백이 생기지 않는다.물론 이미 아는 부분이 많아 가볍게 들었지만 잘하는 개발자 분들을 보면 같은 지식을 본인만의 쉬운 언어로 정리하여 체계적으로 잘 알려주시는 경향이 있다. 이번에도 그러한 점을 느꼈다. 가장 흥미로웠던 부분은 프로젝트 패키지를 나눌 때 였다. 개인적으로 DDD를 학습 한 후로 이상하게 프로젝트 패키지를 나누는 행위가 이전보다 더 부담스럽고 생각이 많아지곤 했다. 하지만 강사님이 프로젝트 패키지를 나누면서 어떤 생각을 하셨고 어떠한 근거로 이렇게 나눴다 라는 말씀을 듣고 DDD원칙에 완전히 준수한 패키지 구성은 아니였지만 꼭 DDD에 걸맞게 패키지를 구성하는게 옳은 것은 아니구나, 역시 은탄환은 없구나 라는 것을 한번 더 느끼며 흥미롭게 시작했다. 테이블 설계역시 프로젝트의 시작은 테이블 설계이다. N:M 관계를 어떻게 풀어나가는지 학습해보자.대표적으로 프로젝트 테이블을 봐보자.(1) project project_skill skill 관계 분석현재 project_skill 테이블에는 다음 컬럼이 있다.project_id (FK) -> project의 project_id를 참조skill_id (FK) -> skill이 테이블은 다대다(N:M) 관계를 풀기 위한 "연결 테이블" 역할을 수행한다. 즉, 한 프로젝트가 여러 개의 기술(skill)을 가질 수 있고, 한 기술(skill)이 여러 개의 프로젝트에 속할 수 있는 관계이다.project_skill 테이블이 N:M 관계를 풀어주는 역할을 한다! 이런 식으로 N:M관계를 서로 1:N , M:1로 만들어주기 위해서는 양쪽의 PK값을 PK로 복합키로 가지고 있는 매핑 테이블이 필요하다.(2) project project_detail 관계 분석project_detail 테이블에는 project_id가 FK로 존재.1:다(1:N) 관계이더. 즉, 하나의 프로젝트가 여러 개의 상세 정보를 가질 수 있음.이런 식으로 RDBMS에 대하여 어떻게 관계를 형성할 것인지 사전에 정확하게 설계하는 습관이 중요하다. 테이블은 운영 상에 정보를 바꾸는 것이 제약이 크기 때문에 신중하자. 깃과 친해지기깃 명령어는 빠르고 간결하게 내가 원하는 실행을 할 수 있게 도와준다. 이에 앞서 IDE에서 제공해주는 기본 GUI기능을 알아봤다.현재 깃 브랜치 정보 보는법View > Tool Windows > Git브랜치 이름 rename하는 법깃허브에 내 프로젝트를 올려두는 법Git > Manage Remote > 팝업창에 git url 입력 후 okcommit 친 것을 push 하는 법아까 View > Tool Windows > Git를 통해 인텔리 제이 하단에 뜬 브랜치 정보 우클릭 하고 push최종!!깃허브 화면 리프래쉬 해보면 프로젝트 올라감을 확인 가능엔티티 추출하기데이터베이스 설계한 내용을 토대로 jpa 엔티티 규격에 맞게 엔티티를 설계 했다.이 내용은 기본적인 jpa지식이 탑재된 내용이라 이론 정리는 생략하였다.미션깃 프로젝트 생성하기앞선 과정을 통해 깃레포트지로리를 작성했습니다.테이블 설계하기1:N 관계의 erp 시스템에 대한 편성된 예산에 대하여 지출하는 프로세스를 설계했습니다. 1주차 회고Keep (만족했고, 앞으로도 지속하고 싶은 부분)기초베이스가 역시 중요하다는 생각이 들었다. 개발을 하다보면 누군가는 되게 짧은 시간에 배우고 잘 하는 사람을 볼 수 있다. 그럴 떄 조급함을 느끼곤 했는데 그 사람의 과거 인생을 봐볼 필요가 있다. 짧은 시간이 단 3개월이라고 치면 그 사람은 짧은 시간 만에 배운게 아닌 지난 몇 년의 경험에 3개월의 지식을 얹었을 거라는 것이다. 개발은 3개월 배웠겠지만 개발자적인 사고방식을 10년했을 수도 있다는 것. 결국 이러한 기초지식이 모여서 나의 체급을 올려야 하는 점을 배운 부분에 만족한다. 전체적인 설계 및 개발 지식을 더 단단하게 배운 거 같아 벌써 앞으로의 여정이 기대됩니다.Problem (아쉬웠던 점)코틀린이라는 언어가 처음이라 다소 익숙하지 않은 문법들이 있다. 결국 자바와 하고 싶은 게 똑같다 보니 이해하는데 어려움이 있지는 않지만 코틀린 특유의 문법을 좀 더 깊게 이해하고 싶다는 생각이 들었다.Try (다음에 시도해볼 점)테이블 구조를 보고 올바른 테이블 설계인지 아닌지를 고민해보는 시간을 가지려고 한다. 결국 테이블 설계는 엔티티 설계에 영향을 주게 되고 프로젝트 전체의 흐름에 영향을 주다보니 중요한 요소인 거 같다.
백엔드
・
코틀린
・
워밍업클럽3기
・
백엔드프로젝트
2024. 10. 27.
0
[인프런 워밍업 클럽 백엔드 스터디 2기] 4주차 발자국
마지막 4주차 발자국을 작성하는 시간이다. Mockito로 Stubbing 하기mock에 대한 원하는 행위(return)을 정의한 다음 내가 테스트하고자하는 서비스에만 집중. ⇒ stubbing이라고 일컷는다.Mockito에서 Stubbing은 모의 객체(Mock)의 메서드가 호출될 때 반환할 값을 미리 설정해 두는 작업을 말한다. 테스트할 때 실제 객체 대신 Mockito로 생성한 모의 객체를 사용하는데, 이때 필요한 메서드의 동작을 미리 정의해 주는 것을 Stubbing이라고 한다. 이렇게 설정하면 실제 메서드가 호출되지 않고, 지정된 값이나 행동을 반환하므로 독립적인 테스트가 가능한 이점이 있다..Stubbing을 설정하려면 when과 thenReturn 또는 thenThrow 메서드를 사용하여 원하는 값을 정의한다. Test Double단위 테스트에서 사용되는 용어로, 테스트하려는 코드의 의존성이나 협력 객체를 대신하여 사용하는 객체를 말한다. 크게 아래 5가지가 있다.Dummy : 아무 것도 하지 않는 깡통 객체Fake : 단순한 형태로 동일한 기능은 수행하나, 프로덕션에서 쓰기에는 부족한 객체 ex) FakeRepository (메모리에 휘발성으로 관리)Stub : 텟트에서 요청한 것에 대해 미리 준비한 결과를 제공하는 객체.Spy : Stub이면서 호출된 내용을 기록하여 보여줄 수 있는 객체다. 일부는 실제 객체처럼 동작시키고 일부만 Stubbing 할 수 있다.Mock : 행위에 대한 기대를 명세하고, 그에 따라 동작하도록 만들어진 객체Mock ≠ Stub공통점은 가짜객체. 차이점 : Stub 은 상태에 대한 검증, Mock은 행위에 대한 검증이다. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이테스트 객체를 생성해주는 다양한 어노테이션이 있다. 크게 Spring 기반 테스트인지 Mockito 기반 테스트인지 구분을 하고 spy 인지 아닌지로 나눌 수 있다.Mokito사용해서 mock만들려면 클래스 상단@ExtendWith(MockitoExtension.class) 를 붙여줘야한다.@Mock:Mockito에서 사용하는 애노테이션으로, 인터페이스나 클래스를 Mock 객체로 생성한다.해당 객체는 실제 동작 없이 사전 설정된 행동만 수행하도록 설정된다.주로 단위 테스트에서 사용@MockBean:Spring Boot에서 사용하는 애노테이션으로, 스프링 컨텍스트에 Mock 객체를 등록한다.스프링 빈으로 주입이 필요한 경우 사용하며, 실제 빈을 Mock 객체로 대체하여 통합 테스트에 적합.@Spy:Mockito에서 사용하는 애노테이션으로, 실제 객체를 기반으로 스파이 객체를 생성한다.원래 메서드를 호출하면서도, 필요한 경우 특정 메서드만 Mocking하여 동작을 변경할 수 있다.@SpyBean:Spring Boot에서 사용하는 애노테이션으로, 스프링 컨텍스트에 실제 객체를 스파이 객체로 등록한다.기존 스프링 빈의 동작을 유지하면서, 특정 메서드만 Stub 처리하여 통합 테스트에서 부분적으로 변경하고 싶을 때 유용하다.@InjectMocks:Mockito에서 사용하는 애노테이션으로, @Mock이나 @Spy로 생성된 객체를 주입해주는 역할을 한다. BDDMockito어? given 절인데 문법이 when이네?Mockito를 감싸고있는 BDD(GIVEN, WHEN, THEN)스타일로 작성만 할 수 있게 이름만 바꾼 상태!! 그래서 그냥 BDDMockito 사용하면 된다. 앞으로는 Classicist VS. Mockist테스트코드를 전적으로 믿냐 아니냐에 대한 견해 차이로 보인다.Mockist : 단위테스트할떄 이미 모든걸 mocking으로 테스트했으니까, 통합테스트할떄는 다 mocking처리해서 기능 보장된 애들은 다 쳐내고 해야하는 것만 짤라서 하자. vs.Classicist : mocking을 다 해버리면 실제 production에서 실 객체가 움직일때의 올바른 동작을 어떻게 보장할 수 있어? 개인적으로 나도 우빈님처럼 Classicist에 더 가까운 편인 거 같다. 테스트 코드는 아무리 완벽하게 하려고 해도 프로덕션 코드에 따라가지 못한다고 생각하고 결국 테스트를 작성하는 사람도 나 자신이기 때문에 허점은 존재할 거 같다. Clean 테스트 코드테스트 코드도 한 문단에 한 주제테스트는 문서다! 글쓰기란 관점에서 봤을때, 한 문단에 하나의 주제를 가지고 있는 게 좋다.완벽하게 제어하기테스트하기 위한 환경을 조성할 때, 모든 조건을 완벽하게 제어할 수 있어야한다.테스트 “환경”의 독립성을 보장하자따라서 given절은 일반적인 생성자만 기입되는게 좋다.테스트 “간”의 독립성을 보장하자두개 이상 테스트 간의 독립성을 보장하자.Test FixtureFixture : given절에 쓰이는 객체들(내가 원하는 결과를 얻기위해 고정해둔 조건들) 이떄 when절에 given절 내용이 들어가는 경우가 많은데 이런 실수를 범하지 말자. 99%의 when절은 한줄이다. (메서드실행) @ParameterizedTest하나의 테스트 메서드를 다양한 매개변수로 반복 실행할 수 있도록 하는 어노테이션사용 예: 여러 입력값에 대해 동일한 로직을 테스트할 때 활용주요 기능:@ValueSource: 간단한 값 배열을 전달(e.g., int, String).@CsvSource / @CsvFileSource: CSV 형식의 데이터나 파일을 통해 여러 매개변수를 전달@MethodSource: 메서드를 통해 테스트 데이터를 전달 @DynamicTest런타임에 테스트 케이스를 생성한다. 정적인 테스트 메서드로 정의되는 것이 아닌 Stream 형식으로 생성한다.사용 예: 테스트 시나리오가 복잡하고 실행할 테스트 케이스의 수나 조건이 실행 중 결정되는 경우에 유용하다.주요 기능:동적 테스트를 생성하려면 @TestFactory 어노테이션 필수!Stream를 반환한다.메서드 내부에서 테스트 케이스와 이름을 동적으로 정의할 수 있습니다. Spring REST DocsAPI의 구조, 기능, 요청 및 응답 형식 등을 문서화AsciiDoc의 도움을 받아 MarkDown문법으로 작성하고 라이브러리를 의존성 주입받아 html로의 변환도 쉽게 할 수 있다.Swagger vs. REST DocsSwagger적용이 쉽다.문서에서 바로 api호출을 수행할 수 있다.프로덕션 코드에 침투적이다.신뢰도가 떨어진다.REST Docs테스트를 통과해야 문서가 만들어지므로 신뢰도가 높다.프로덕션 코드에 비침투적이다.코드의 양이 많고 설정이 어렵다.강의에서 여러 설정을 잡고 최종적으로 REST Docs문서를 생성하여 브라우저를 통해 확인해보았다. 테스트 과정을 거치며 각각의 문서 조각들이 모여 하나의 문서가 되는 것이 재밌었다. 4주차 회고Keep (만족했고, 앞으로도 지속하고 싶은 부분)테스트 코드를 짤 때 어떤 점이 문서화를 할 때 좋을지 다시 한번 생각해볼 수 있으며, 각종 어노테이션을 습득할 수 있었다. 더불어 api를 많이 짤 일이 생길 텐데 이렇게 REST Docs를 통해 문서 규격을 자동화하여 관리할 수 있다는 점이 너무 유용하고 값진 경험이였다. 앞으로 토이프로젝트를 하면서도 많이 사용해볼 예정이다..Problem (아쉬웠던 점)전반적으로 이번 강의를 마치면서 강사님의 생각을 내가 완전히 따라가지는 못했다는 생각이 많이 든다. 정말 훌륭한 강의를 펼쳐주시지만 내가 모든 것을 내꺼로 체화시키는 과정은 별도로 필요해보인다. 남이 하는걸 봤을때 쉬워보이면 그 사람이 정말 잘하는 거라고 하던데 나도 그런 경지가 되고 싶다는 생각이 들었다. Try (다음에 시도해볼 점)전반적으로 배운 내용을 적용해본 토이프로젝트를 진행할 예정이다. 클린코드와 테스트코드 원칙을 기반으로 서비스를 런칭시켜볼 예정이다. 너무 많은 것을 배워 행복한 일주일이였다.
백엔드
・
워밍업클럽백엔드2기
・
발자국
・
몰입하는개발자
・
테스트코드
2024. 10. 22.
0
[인프런 워밍업 클럽 2기] Layered Architecture에서의 Testing 정리
Layered Architecture의 레이어별 특징 및 테스팅 방법 정리예시: 음식 배달 서비스각 레이어를 음식 배달 서비스의 역할로 설명한다. 음식 배달 서비스를 통해 사용자가 음식을 주문하고, 음식점에서 음식을 준비하고, 배달원이 고객에게 음식을 전달하는 과정을 생각해 본다. Persistence Layer특징비지니스 가공 로직이 포함되어서는 안 된다.이 레이어는 데이터베이스와 상호작용하여 음식점의 메뉴, 고객 정보, 주문 기록 등을 저장하고 관리한다. 마치 식당의 재료 창고처럼, 데이터의 상태를 정확히 관리하고 필요한 정보를 보관한다. 창고에서는 식당의 주방장이 재료를 요청하면, 정확한 재료를 꺼내주는 역할을 한다. 데이터의 가공은 하지 않고, 필요한 데이터만 정확하게 주고받는 것이 이 레이어의 역할이다.테스트 방법- 단위 테스트: 재료 창고에서 특정 재료를 꺼내거나, 새로운 재료를 추가할 때 그 과정이 제대로 이루어지는지 검증한다. Mocking을 통해 창고에 직접 접근하지 않고, 데이터가 올바르게 반환되는지 확인한다.- 통합 테스트: 실제 창고에서 재료를 꺼내고 추가하는 테스트를 진행한다. 예를 들어, '김치 찌개 재료'를 창고에 추가하고, 해당 재료를 제대로 꺼낼 수 있는지를 확인한다. Business Layer특징트랜잭션을 보장해야 한다.이 레이어는 주방에서 음식의 조리 과정을 담당한다. 사용자 주문에 따라 어떤 메뉴를 어떻게 조리할지 결정하고, 레시피에 따라 재료를 가공하거나 조리 과정을 관리한다. 주방장은 여러 재료를 받아서 맛있는 요리를 만들어내는 역할을 한다. 마치 식당 주방장이 음식의 맛과 품질을 관리하듯, 비즈니스 로직을 통해 데이터와 요구사항을 처리한다.테스트 방법- 단위 테스트: 주방장이 다양한 재료로 요리를 만들 때 레시피에 따라 올바르게 조리하는지 검증한다. Mocking을 통해 창고에서 직접 재료를 받지 않고, 주방에서의 조리 과정 자체에 집중한다.- 통합 테스트: 주방과 창고가 함께 작동하며 올바른 음식을 내놓는지를 확인한다. 예를 들어, '된장찌개' 주문이 들어왔을 때 창고에서 된장과 야채를 받아, 조리 과정을 거쳐 최종 요리가 완성되는지를 검증한다. Presentation Layer특징MockMvc를 통해 내가 테스트하고자하는 부분에 집중한다.상위레이어가 하위 레이어를 알고 있는 것은 당연하지만, 하위레이어가 상위레이어를 알고 있는 것은 의존성이 강한 구조이다.이 레이어는 완성된 음식을 고객에게 전달하는 역할을 한다. 주로 배달원이 주문한 음식을 정확하게 고객에게 전달하며, 사용자가 원하는 방식대로 음식이 전달되는지 책임진다. 고객의 요구사항을 주방에 전달하고, 그 결과를 받아 다시 고객에게 전달하는 역할을 한다. 배달원이 고객에게 주문한 음식을 가져다주는 것처럼, 이 레이어는 사용자와 가장 가까운 곳에서 상호작용을 수행한다.테스트 방법- 단위 테스트: 배달원이 주문한 음식과 고객의 요청을 제대로 처리하는지 검증한다. Mocking을 통해 주방이나 창고에 접근하지 않고, 배달원과 사용자의 상호작용에 집중한다.- 통합 테스트: 배달원, 주방, 창고가 함께 작동하면서 사용자의 주문을 제대로 처리하는지 검증한다. 예를 들어, 고객이 '비빔밥'을 주문했을 때, 주방과 창고의 도움을 받아 배달원이 정확하게 비빔밥을 전달하는지를 확인한다. 흐름도사용자 Presentation Layer (배달원 역할) Business Layer (주방 역할) Persistence Layer (재료 창고 역할)- 사용자(고객)는 Presentation Layer를 통해 주문을 요청한다.- Presentation Layer는 Business Layer에 주문 내용을 전달한다.- Business Layer는 Persistence Layer에서 필요한 데이터를 가져와 주문에 따라 데이터를 가공한다.- 최종적으로 Presentation Layer는 사용자가 원하는 형식으로 결과를 전달한다. - 각 레이어는 역할을 명확히 나누어, 서로에게 필요한 정보를 정확하게 전달하는 데 집중한다.
웹 개발
・
워밍업클럼2기
・
몰입하는개발자
・
테스트코드
・
TDD
2024. 10. 20.
0
[인프런 워밍업 클럽 백엔드 스터디 2기] 3주차 발자국
워밍업 클럽 백엔드 스터디 2기 3주차 발자국 입니다.본격적인 TDD 가이드에 대하여 배우기 시작했습니다.테스트는 왜 필요할까?테스트 = 귀찮다?프로그램이 커지면 수동테스트의 정확도가 어떨까?사람이 할거야?변화가 생기는 매순간마다 모든 팀원이 동일한 고민을 해야한다면 소프트웨어의 신뢰도가 낮아질 가능성이 높다. 올바른 테스트 코드자동화 테스트로 비교적 빠른 시간 안에 버그를 발견할 수 있고, 수동 테스트에 드는 비용을 크게 절약할 수 있다.소프트웨어의 빠른 변화를 지원한다.팀원들의 집단 지성을 팀 차원의 이익으로 승격시킨다.가까이 보면 느리지만, 멀리 보면 가장 빠르다.단위테스트란작은 코드(클래그 or 메서드) 단위를 독립적으로 검증하는 테스트단위테스트는 검증속도가 빠르고 안정적이다.우리는 JUnit5 와 AssertJ 를 사용하여 테스트 코드를 작성해보았다. 테스트 케이스 세분화하기질문하기 : 암묵적이거나 아지 드러나지 않은 요구사항이 있는가? 해피케이스와 예외케이스에 대하여 테스트 케이스를 세분화 해야한다.-> 경계값 테스트라는 개념을 배웠다.어떠한 정수가 있는데 정수가 3이상일 때, A라는 조건이 성립한다면?⇒ 테스트를 4나 5로 테스트 하는게 야니고 3에 대하여 테스트를 작성하는게 맞다.⇒ 예외 케이스는 2나 1이나 -1과 같은 경계값보다 아래의 경우의 수로 예외케이스를 짜는게 맞다. 테스트하기 어려운 영역 분리하기외부세계에 관련된 도메인은 테스트하기 어려우니 분리하여 가능한 것에 집중한다.input 과 output이 외부세계에 영향을 주거나, 외부세계에 영향을 받는 경우에는 테스트하기 어렵다.ex) 표준출력, 메시지발송, 데이터베이스에 기록하기 등.. 강의에서는 "현재시간" 은 테스트를 돌리는 시간이 바뀜에 따라 매번 결과값이 달라질 수 있으므로 정확한 테스트가 어려워 프로덕트 코드에는 현재시간을 매개변수로 넣고, 테스트할 때는 테스트 하고자 하는 시간을 매개변수로 세팅하여 분리한다. 즉, 테스트 어려운 조건이 생기면 테스트 어려운 영역을 외부로 분리하여 조치한다.TDD프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현 과정을 주도하도록 하는 방법론RED - GREEN - REFACTOR위 과정으로 TDD가 이루어진다. 실패케이스를 먼저 짜고, 통과를 위한 통과 케이스를 짜고, 리팩토링하고 이를 반복한다.선기능 구현, 후 테스트의 문제점테스트 자체의 누락 가능성(아 테스트 짤 시가니 없네)특정 테스트 케이스만 검증할 가능성(해피케이스만 생각)잘못된 구현을 다소 늦게 발견할 가능성 테스트는 [문서]다.언어가 사고를 제한한다.프로덕션 기능을 설명하는 테스트 코드 문서다양한 테스트 케이스를 통해 프로덕션 코드를 이해하는 시각과 관점을 보안해피케이스와 예외케이스를 생각하여 더 깊게 이해할 수 있다.어느 한 사람이 과거에 경험했던 고민의 결과물을 팀차원으로 승격시켜서, 모두의 자산으로 공유할 수 있다.테스트케이스를 통해 고민의 결과를 공유하여 소스코드를 관리할 수 있다. DisplayName을 섬세하게테스트 하고자 하는 내용을 명확하게 기술하자문장형태로 작성하자!테스트 행위에 대한 결과까지 기술한다.도메인 용어를 사용하여 한층 추상화된 내용을 담기테스트의 현상 중점 기술: "특정 시간 이전에 주문을 생성하면 실패한다."여기서는 "실패한다"는 구체적인 현상을 강조한다. 테스트가 어떤 상황에서 실패하는지를 중심으로 표현한 것이다. 하지만 이 표현은 테스트가 도메인의 규칙이나 의도를 명확하게 설명해주지 못할 수 있다. 실제 비즈니스 로직의 핵심 규칙보다는 실패 여부에 집중하게 되는 문제가 있게된다.도메인 관점에서의 기술: "영업 시작 시간 이전에는 주문을 생성할 수 없다."이 표현은 현상보다는 도메인의 규칙을 명확하게 기술. "영업 시작 시간 이전에는 주문을 생성할 수 없다"는 표현은, 해당 비즈니스 로직이 적용되는 이유나 규칙을 이해하는 데 도움이 되며, 비즈니스 도메인에서의 규칙을 중심으로 설명하는 방식이다. 레이어드 아키텍쳐와 테스트Presentation Layer - Business Layer - Persistence Layer관심사의 분리를 위해 레이어를 분리한다.기본적인 JPA 엔티티를 설계하고 테스트하고자하는 레이어를 분리하였다.Persistence Layer 테스트기본적인 CRUD를 구성한 후 데이터베이스와의 연동테스트를 하였다.EnableJpaAuditing을 통하여 테이블의 상태를 트랙킹하고 H2 테이버베이스 콘솔과 비지니스 구현 로직이 정상 작동하는지 확인하였다.Business Layer 테스트비지니스 로직을 구현하는 역할 Persistence Layer와의 상호작용(data를 읽고 쓰는 행위)를 통해 비지니스 로직을 전개시킨다. 트랜잭션을 보장해야한다.도메인 로직에 대한 테스트 코드를 작성하였다. 이때 트랜잭션에 대한 관리가 중요했다.상품을 주문할 때, 제고차감에 대한 로직에서 트랜잭션 관리의 중요성을 느꼈는데 기본적인 테스트코드에서의 @Transactional 개념은 이러하다.트랜잭션 관리: @Transactional을 사용하면, 해당 테스트 메서드가 실행될 때 자동으로 트랜잭션이 시작된다. 그리고 테스트가 완료되면, 해당 트랜잭션은 롤백처리.데이터 정리: 트랜잭션이 롤백되므로, 테스트 중 데이터베이스에 삽입되거나 수정된 데이터는 테스트가 끝나면 모두 사라집니다. 따라서, 별도의 정리 작업이 필요 없게된다.. 테스트 격리성: 트랜잭션 범위 내에서 테스트가 실행되고, 롤백을 통해 테스트 이전 상태로 되돌아가므로, 테스트 간의 데이터 격리성이 자연스럽게 유지된다.이렇게 보면 무조건 트랜잭션 어노테이션을 사용하는 것이, AfterEach를 통한 수동 삭제보다 이점이 크다는 생각이 들지만, 테스트코드에만 트랜잭션이 잡혀있고 실제 프로덕션 코드에는 트랜잭션이 안 잡혀있을 수 있는 위험성이 있으므로 팀원 내부적인 공지나 개발자의 인지가 필요하다.이런 점을 놓치면 심각한 상황이 발생할 수 있다. 테스트코드는 통과했지만 실제 운영에는 버그가 생기는 것이다. 예를 들어, 주문을 생성하고 주문에 포함된 상품이나 재고를 업데이트하는 작업이 순차적으로 실행될 때, 중간에 예외가 발생하면 앞서 실행된 작업은 롤백되지 않아 장애가 있을 것이다. 3주차 회고Keep (만족했고, 앞으로도 지속하고 싶은 부분)테스트 코드의 기본적인 Given When Then 방식이 익숙해짐을 느꼈다. 더불어 JPA와 Spring Data JPA에 대한 개념을 다시 한번 다지는 기회도 갖을 수 있었다. 또한, 단위테스트와 통합테스트에 대한 개념이 실무에서는 어떻게 적용되어야 하는지 인지할 수 있었다..Problem (아쉬웠던 점)기본적으로 JUnit 과 AssertJ의 메서드에 아직 친숙한 느낌은 아닌 거 같다. 그러다보니 강의를 들으며 도메인을 따라가면서 코드까지 신경쓰는 것이 어려운 부분이 있었다. 천천히 다시 한번 강의를 들으며 다시 학습하는 과정이 필요해보인다. Try (다음에 시도해볼 점)세부적으로 여러가지를 알려주셔서 좋았다. 다음에는 개인프로젝트로 동시성문제에 대해서 좀 더 고찰해보는 시간을 가지고 싶다. 지나가면서 말씀해주신 ptimistic lock / pessimistic lock 에 대해서도 공부해보고 싶다.
백엔드
・
워밍업클럽2기
・
몰입하는개발자
・
백엔드
・
테스트코드
・
TDD