소개
안녕하세요 ☺️
몰입을 즐기는 개발자, 박우빈입니다.
(현) 캐치테이블(와드) 소프트웨어 엔지니어
(전) 우아한형제들 소프트웨어 엔지니어
우아한테크코스 3기, 4기 리뷰어 / 우아한테크캠프pro 1기 리뷰어
강의
전체3로드맵
전체1수강평
- 항상 좋은 강의 감사합니다~!
HG Kim
2024.10.16
0
게시글
질문&답변
2024.10.22
Presentation Layer 테스트 관련 질문 있습니다!
안녕하세요, 박문순 님! 현재 Presentation Layer 테스트에서 create할때에는 httpstatus만 확인하는데 보통 Presentation Layer 테스트의 경우 상태값만 확인하고 실제로 db에 저장되어 있는지 확인하지는 않을까요? 제가 소개드린 표현 계층 테스트 방식은 단위 테스트에 가깝고, 실제로 DB에 데이터를 저장하지 않습니다. (Service를 mocking 했으니까요!) 강의에서 설명드렸듯 외부에서 들어오는 파라미터의 유효성을 검증하는 것이 그 목적이기 때문입니다. 만약 확인한다면 통합테스트가 필요할 것 같은데 약간 다른 결의 질문이지만 통합테스트시에 spring Security 인증을 포함해서 해야할까요 아니면 제외하고 해야할까요? 만약 제외하고 해야한다면 통합테스트시 spring Security를어떻게 제외해야 하는지도 여쭤보고 싶습니다 Security를 포함해서 검증할 것인지, 제외하고 검증할 것인지도 필요에 따라 선택하시면 됩니다. 아래 AI 인턴이 잘 소개해준 것 처럼, @WithMockUser 등의 키워드로 검색해보고, 적용해 보시면 좋을 것 같아요. 감사합니다. 🙂
- 0
- 2
- 25
질문&답변
2024.10.22
질문 제목을 뭐라 적어야할지 모르겠습니다. 죄송합니다
안녕하세요, PrivilegeEscalate 님! 좋은 질문이네요 ㅎㅎ 아래 추가 내용 남겨주신 부분에서 시작하자면, 아 리팩토링 (1) - 추상화 레벨 25분 10초쯤부터 해당과 비슷한 내용이나오네요!! 그렇다면 왜 StudyCafeLockerPass 가 아닌, StudyCafePass 에 질문을 던진 이유를 알 수 있을까요? 메서드의 설계는 곧 도메인에 대한 이해에서부터 시작되는데요. (제가 만들었지만..) 제가 이 도메인을 이해한 내용 중 하나는, " StudyCafeLockerPass 는 StudyCafePass 에 종속적이다" 입니다. 실제로 사물함 이용권은 스터디카페 이용권을 구입하지 않으면 사용할 수 없기 때문이죠. 두 객체 A와 B가 동등하고, 크게 관련이 없는 상태에서 내부 타입만 공통으로 가지고 있다면, 말씀주신 V2 처럼 type, duration 만 넘겨서 해당하는 pass를 찾았을 것 같은데요. 객체 A와 B가 종속적인 관계라고 저는 해석했기 때문에, 좀 더 주체가 되는 Pass가 LockerPass를 받아서 해당 데이터를 꺼내어 처리하는 방식을 선택하였습니다. 정답이 없고, 도메인을 이해하는 방식에 따라 달라질 수 있는 점이긴 한데요 ㅎㅎ 다만 메서드 설계 시 제가 설명드린 것처럼 명확한 이유에 근거하여 설계해보는 습관을 들이는 게 중요한 것 같습니다. 도움이 되셨기를 바랍니다. 감사합니다. 🙂
- 0
- 2
- 71
질문&답변
2024.10.22
영속성 계층과 E2E 테스트에 대해 질문이 있습니다.
안녕하세요, 종운 님! 먼저 영속성 테스트 관련 질문 부터 드리고자 합니다. 취업을 하기 전에 취준을 하는 상황에서는 H2 DB로만 해소 할 수 있는 상황이 많았던 것 같습니다. 하지만 실무에 들어오니 생각보다 Native Function을 사용하는 경우가 있고, 버전 문제로 각 DB에 있는 연산자가 제대로 동작하지 않는 일 (Dialect 이슈) 도 적지 않게 볼 수 있었습니다. 아직까지는 제 경험에서는 Test Container를 사용하여 실 상황과 유사한 DB를 사용하는 것이 그나마 합리적인 방법으로 생각 을 하고 있습니다. 하지만, 또 컨테이너가 뜨다보니 테스트하는데 걸리는 시간이 상당한 것도 단점으로 다가오기는 하더라구요. 맞습니다. 결론부터 이야기하자면, 저는 도메인마다 취해야 하는 전략이 다르다고 생각해요. 제가 소개드린 H2를 사용한 테스팅 방식은 장점이 명확하고, 대부분의 케이스를 커버할 수 있는 방식이라고 생각해요. (80~90%) 말씀주신 것처럼 특수한 상황에 특정 데이터베이스(ex. MySQL)와의 차이 때문에 테스트가 어려운 상황이 발생할 수도 있는데요. 결국은 Dialect를 사용하지 않는 방향으로 단순화해서 기능을 리팩토링하거나, 도메인 특성상, 혹은 기타 이유로 변경하기 어렵고 반드시 테스트를 진행하는 것이 좋겠다고 생각한다면 속도 문제를 트레이드오프로 가져가면서 TestContainer를 사용하는 것이 맞다고 생각합니다. 일반 케이스를 H2로 테스트하고, 해당 케이스만 별도로 테스팅하는 전략도 취해볼 수 있을 것 같고요. (팀 내 논의에 따라서는 관련 케이스가 적고 중요도가 낮으면, 자동화된 테스트 말고 필요할 때 수동 테스트를 진행하자, 도 합리적인 결론이 될 수도 있겠죠..ㅎㅎ 그럴 때 수동 테스트를 진행하기 편한 환경을 만드는 것은 또 별개의 (필요한) 이야기이고요.) 이어서, E2E 테스트 관련 질문입니다. 비즈니스 계층에서의 통합 테스트가 작성이 되었다 면 아직까지는 우빈님의 생각과 동일하게 프레젠테이션 영역에서는 통합 테스트를 하지 않아도 괜찮지 않을까? 라는 생각을 가지고 있는데요. 하지만, 종종 테스트 관련 여러 서적이나 토론등을 보면 E2E 테스트는 중요하다는 관점을 가지고 있는 글이나 영상을 종종 찾아 볼 수 있었고, 무엇보다 저희 팀원분들중에서도 "E2E 테스트를 하는게 아니라면 프레젠테이션 레이어를 테스트 할 필요가 있어?" 라는 질문을 받았을 때 다음과 같은 생각이 들었습니다. "그러네.. 지금까지는 거의 문서화를 목적으로 작성을 했었는데, 문서화를 RestDocs, RestDocs to Swagger(OpenApi Spec) 를 하는게 아니라면 작성 할 필요가 있을까?" 라는 의문이 떠올랐습니다. 혹시 이 부분에 대해서 어떻게 생각하시는지 우빈님의 소견을 듣고 싶어서 긴 글로 질문을 드리게 되었습니다. E2E 테스트, 혹은 인수 테스트도 마찬가지로 저는 도메인에 따라 다르게 취해야 할 전략이라고 생각해요. 예를 들어, Server to Server(S2S)로 다른 서버에 API를 제공하는 도메인이 있다고 한다면, 그리고 API 간 특별히 관계가 없는 독립적인 API를 구성하고 있다면, 서비스 통합 테스트로 대부분의 케이스가 커버될 것이라 기대해볼 수 있겠습니다. 반대로, 프론트엔드와 직접적으로 소통하고, 일반 사용자들이 다이렉트로 이용하게 되는 도메인이라면, E2E, 인수 테스트의 중요도가 굉장히 높을 수 있습니다. 개발 관점을 넘어 사용자 관점에서 여러 케이스에 대한 테스팅이 필요하고, 실제 운영 환경에서의 조건을 최대한 재현하여 검증하는 것이 중요하기 때문입니다. 또 여러 API가 일련의 시나리오를 가지고 순차적으로, 혹은 병렬적으로 호출되는 경우, 해당 시나리오를 기반으로 테스트를 진행하는 것도 필요할 수 있습니다. (1번 API에서 응답을 받고, 그 응답을 가지고 다시 2번 API에 요청하는 등, ex. 회원가입-로그인-마이페이지 접근) (S2S, C2S와 같이 이분법적으로 나눈 것은 이해를 돕기 위한 예시입니다.) 고로 해당 사항도, 팀 내 논의에 따라 잘 결정하면 되는 사항이라고 생각해요. 도움이 되셨기를 바랍니다. 감사합니다. 🙂
- 0
- 1
- 36
질문&답변
2024.10.22
builer 생성 방식 메서드 분리
안녕하세요, ykm8864 님! 테스트 코드에서 createProduct()와 같이 메서드를 별도로 구성한 이유는, 테스트 코드 자체의 가독성 때문입니다. 지금이야 예제가 간단하지만, 실제로 복잡한 프로젝트에서는 given절에 정말 많은 내용이 들어갈 수 있는데요, 그때마다 모든 객체를 빌더 패턴으로 그대로 생성하면 코드량이 상당히 많아집니다. 오히려 상황에 맞는 메서드를 만들어 사용하면, 메서드명으로 어떤 특징을 가지고 있는 객체인지를 나타내줄 수도 있기에, 필요한 파라미터에 맞게 메서드를 만드는 편입니다. 도움이 되셨기를 바랍니다. 감사합니다 🙂
- 0
- 2
- 24
질문&답변
2024.10.20
Classicist VS. Mockist
안녕하세요, 양성빈 님! 제가 테스트할때는 repository부분의 쿼리메서드나 jpql로 작성한 코드들은 따로 테스트를 하지 않고 QueryDSL같은 외부 라이브러리를 사용할때만 단위 테스트를 진행합니다. 아주 단순한, 쿼리가 예측되는 메서드라면 비용을 고려하여 테스트를 스킵할 수도 있겠으나, 결국 런타임 시점에 생성되는 SQL 쿼리를 검증하지 않고는 기능을 보장하기가 어렵습니다. 쿼리 메서드 : Spring data JPA에서 제공하는 기능으로 결국 SQL를 생성해주는 것이니, 복잡한 쿼리일수록 예측이 어려울 수 있습니다. JPQL : 문자열로 작성되기에, 단순한 오타 등 동작하지 않을 가능성이 쿼리 메서드보다 더 큽니다. QueryDSL : 컴파일 타임에 어느 정도 기능 보장을 해주나, 마찬가지로 최종 생성되는 SQL에 대한 검증이 필요합니다. 그래서 사실 어떤 방식을 사용하든, 런타임 시점의 기능을 보장하기 위해서는 테스트가 필수라고 생각해요. 그리고 비즈니스 레이어에 대해서는 위의 repository를 mocking하여 사용하고 컨트롤러 부분에서 통합테스트를 진행합니다. 위에 말씀드린 이유로 인해, 복잡한 Repository의 쿼리 뿐만 아니라, 다양한 Repository, 비즈니스 로직이 얽힌 서비스 계층에서 Repository를 mocking하여 테스트하는 것은 저는 조금 위험할 수 있다고 생각해요. 저도 테스트를 작성하지 않고 기능을 개발했을 때, 쿼리가 실제 생각한대로 동작하지 않아 결국 시간을 더 사용하게 되었던 경험이 많습니다. Controller 단에서 Repository를 포함한 전체 통합 테스트를 한다고 하더라도, Repository 단위 레이어 테스트로 보장할 수 있는 케이스를 가장 바깥 레이어의 통합 테스트 케이스로 커버하는 것은 비용 측면에서도 비효율적인 것 같아요 ㅎㅎ 도움이 되셨기를 바랍니다. 감사합니다 🙂
- 0
- 1
- 85