블로그

whffkaos007

워밍업 클럽 2기 BE 클린코드&테스트 - 회고 3회

이 글은 박우빈님의 강의를 참조하여 작성한 글입니다. 벌써 3주차가 되었습니다. 읽기 좋은 코드 관련 강의가 마무리되고 실용적인 테스트 강의를 시작했습니다. 부족한 부분도 있겠지만 열심히 달려온 과정을 적겠습니다. 강의 목적테스트 코드의 중요성과 작성해야 하는 이유테스트 코드를 작성하는 방법  테스트의 필요성테스트는 기능에 대한 부가적인 요소이다. 실제로는 기능을 구현하기 바쁘다. 그런데도 왜 테스트의 중요성이 강조될까?테스트를 작성하면 위와 같은 단점이 있다. 반대로 테스트를 작성하지 않는다면 어떻게 될까? 커버할 수 없는 영역 발생경험과 감에 의존 → 인간이기에 이럼.늦은 피드백 → 수동으로 테스트 해야 함.유지보수 어려움 → 확장, 수정이 일어난다면 어디까지 영향을 미칠지 모름소프트웨어 신뢰성 낮음 → 언제 어디서 버그가 터질지 불안함  테스트 코드를 작성하지 않는다면변화가 생기는 매순간마다 발생할 수 있는 모든 Case를 고려해야 한다.변화가 생기는 매순간마다 모든 팀원이 동일한 고민을 해야 한다.빠르게 변화하는 소프트웨어의 안정성을 보장할 수 없다.테스트 코드가 병목이 된다면프로덕션 코드의 안정성을 제공하기 힘들어진다.테스트 코드 자체가 유지보수하기 어려운, 새로운 짐이 된다.잘못된 검증이 이루어질 가능성이 생긴다. 테스트 코드를 작성하지 않는다면변화가 생기는 매순간마다 발생할 수 있는 모든 Case를 고려해야 한다.변화가 생기는 매순간마다 모든 팀원이 동일한 고민을 해야 한다.빠르게 변화하는 소프트웨어의 안정성을 보장할 수 없다.테스트 코드가 병목이 된다면프로덕션 코드의 안정성을 제공하기 힘들어진다.테스트 코드 자체가 유지보수하기 어려운, 새로운 짐이 된다.잘못된 검증이 이루어질 가능성이 생긴다.   그럼 올바른 테스트 코드를 서비스에 적용시킨다면 어떤 결과를 가져올까?올바른 테스트 코드는자동화 테스트로 비교적 빠른 시간 안에 버그 발견, 수동 테스트에 드는 비용을 크게 절약소프트웨어의 빠른 변화를 지원한다.팀원들의 집단 지성을 팀 차원의 이익으로 승격시킨다.가까이 보면 느리지만, 멀리 보면 가장 빠르다.    테스트 케이스 세분화하기 테스트에는 해피 케이스와 예외 케이스가 있다.   우리는 요구사항대로 기능을 구현할 때, 이외 여러 경우를 고려해야 한다 예를 들어 커피 주문하기에 대한 기능을 구현할 때는 커피의 개수가 1 이상이여야 한다는 숨겨진 조건이 있다.이처럼 숨겨진 조건을 고려하여 작성할 때 도움이 되는 것은 경계값 테스트이다. 경계값 : 범위(이상, 이하, 초과, 미만), 구간, 날짜 등경계값을 기준으로 테스트를 고려해야 기능(도메인)에 대한 명확한 인지에 도움이 되며 예외 상황도 쉽게 파악할 수 있다.   테스트하기 어려운 영역을 분리하기테스트 코드는 작성하기 쉬운 부분과 어려운 부분이 존재한다. 예를 들어 오전 10시부터 오후 2시까지만 주문이 가능한 조건이 있다 가정하자. order(List<Item> items){ LocalDateTime now = LocalDateTime.now(); if(now < 오전 10시 || 오후 2시 < now){ // 예외 발생 } ... } 위 메서드에 대한 테스트를 진행하면 어떻게 될까?테스트를 실행하는 시간에 따라 성공 여부가 달라질 것이다.그렇다면 이처럼 테스트하기 어려운 상황이 생기면 어떻게 해야 할까?바로 테스트하기 어려운 부분을 외부로 분리해야 한다.  order(List<Item> items, LocalDateTime time){ if(time< 오전 10시 || 오후 2시 < time){ // 예외 발생 } ... } 위 코드처럼 시간이란 테스트하기 어려운 영역을 외부로 분리하여 파라미터로 받는다. 이렇게 코드를 작성하면 테스트하는 시간마다 성공 여부가 달라지지 않는다.테스트라는 기능을 온전히 수행할 수 있을 것이다. 이처럼 우리는 테스트하기 어려운 부분이 있다면 이를 외부 세계로 분리하여 테스트하기 쉽게 만들어야 한다.그럼 이런 어려운 부분은 무엇이 있을까? 어려운 영역관측할 때마다 다른 값에 의존하는 코드현재 날짜/시간, 랜덤 값, 전역 변수/함수, 사용자 입력 등외부 세계에 영향을 주는 코드표준 출력, 메시지 발송, 데이터베이스에 기록하기 등쉬운 영역 → 순수함수(pure fuction)같은 입력에는 항상 같은 결과외부 세상과 단절된 형태테스트하기 쉬운 코드이러한 영역은 위와 같이 있지만 직접 경험하면서 어떤 부분을 분리하는 것이 더 좋을 지에 대한 고민을 해야 시야를 기를 수 있다. TDD:Test Driven Development TDD는 위 구조를 통해 테스트 코드를 작성하는 것이다. 구현 → 테스트 순이 아닌테스트 → 구현 순으로 진행하는 방법이다.왜 TDD가 좋을까? 어떤 가치를 지니지?가장 큰 가치 중 하나는 빠른 피드백이다. 선 기능 구현, 후 테스트 작성테스트 자체의 누락 가능성특정 테스트 케이스만 검증할 가능성(해피 케이스)잘못된 구현을 다소 늦게 발견할 가능성테스트를 먼저 작성한다면 테스트에 대한 고려에 대한 시야를 가질 수 있다. 선 테스트 작성, 후 기능 구현복잡도 낮은 테스트 가능한 코드로 구현할 수 있게 한다.유연하며 유지보수가 쉽다.쉽게 발견하기 어려운 엣지 케이스를 놓치지 않게 해준다.구현에 대한 빠른 피드백을 받을 수 있다.과감한 리팩토링이 가능하다.  TDD : 관점의 변화지금까지 기능 구현과 테스트의 관계를 봤을 때, 우리는 아래와 같이 기능과 테스트가 상호작용하는 구조를 추구해야 한다.기존에는 테스트는 구현부의 검증을 위한 보조 수단이었다면 TDD를 이용하면 테스트와 상호 작용하며 발전하는 구현부를 가질 수 있다.클라이언트 관점에서의 피드백을 주는 Test Driven.  테스트는 문서다. 문서란?프로덕션 기능을 설명하는 테스트 코드 문서다양한 테스트 케이스를 통해 프로덕션 코드를 이해하는 시각과 관점을 보완어느 한 사람이 과거에 경험했던 고민의 결과물을 팀 차원으로 승격시켜서, 모두의 자산으로 공유할 수 있다.우리는 테스트 코드를 통해 해당 기능이 어떻게 동작하는 지 파악할 수 있다. 해피 케이스와 예외 케이스를 통해 코드(도메인 지식)를 인지하는데 도움을 얻을 수 있고 기존의 테스트를 통해 잘못된 부분이나 놓친 부분을 파악할 수 있다.우리는 항상 팀으로 일한다. 팀원에게 어떻게 보일 지 항상 고민하면서 작성하는 습관을 기르자.DisplayName을 섬세하게@DisplayName("음료 1개 추가 테스트") // 1 @DisplayName("음료 1개를 추가하면 주문 목록에 담긴다.") // 2 우리는 신규 입사자다. 서비스의 테스트 코드를 봤을 때 1, 2 중 어떤 것이 테스트 코드의 담긴 의미를 더 많이 전달해주는가?바로 2번이다. 왤까? 명사의 나열보다 문장으로 표현하기우리는 좀 더 명확한 의미를 파악할 수 있다. 정보의 생략의 없기 때문이다.테스트 행위에 대한 결과까지 기술하기이 또한 해당 기능에 대한 모든 정보를 알기 위해 행위에 대한 결과까지 기술하자.도메인 용어를 사용하여 한층 추상화된 내용을 담기(메서드 자체의 관점보다 도메인 정책 관점으로)테스트의 현상을 중점으로 기술하지 말 것  특정 시간 이전에 주문을 생성하면 실패한다. // 1 영업 시작 시간 이전에 주문을 생성하면 생성할 수 없다. // 21, 2 중 당연히 2가 더 추상화된 내용을 전달해준다. 우리가 도메인 지식을 이해하는데 더욱 도움을 준다.또한 ‘실패한다’와 ‘생성할 수 없다’를 보자. 실패한다는 것은 도메인에 대한 정보가 아니다. 단순히 테스트의 성공, 실패라는 결과에 의존한 것이다. 우리는 도메인의 정보를 전달할 수 있게 주의해야 한다.  BDD 스타일로 작성하기given - when - then → ‘테스트의 준비 - 행위 - 결과’ 를 의미한다.명확하게 표시해 줌으로써 테스트 코드를 좀 더 이해하기 쉽다.  Test의 양면성과 바라봐야 할 시각(개인 정리)이처럼 테스트에 대한 이점과 작성법이 있다. 하지만 테스트 또한 비용이다. 테스트가 오히려 기능 구현보다 비용이 비쌀 수도 있고 그렇기에 이를 단순 테스트의 용도로 바라보거나 기능 구현에 편향된 모습을 보이며 테스트 작성이 오히려 불필요하다는 반론도 많다. 하지만 우리는 지금 당장이 중요한 것이 아니다. 서비스가 운영된다면 종료되기 전까지 성장할 것이다. 또한 사용자가 많아지고 서비스의 규모가 커질수록 우리 코드는 더 많은 상호 협력을 요구하기에 결합도가 커지기 마련이다.이에 따라 장애가 발생할 확률도 높다. 테스트를 작성할 때, 항상 고민하는 습관이 있어야 장애의 발생을 예방할 수 있다. 테스트를 단순 검증의 역할로만 바라보지 말고 문서의 역할까지 크게 바라보자. 그럼에도 비용은 무시할 수 없다. 비용과 비용에서 오는 이점을 고려하여 우리는 테스트를 다루는 것도 필요한 요소라고 생각한다. 

백엔드테스트테스트필요성테스트작성법

유진

인프런 워밍업 클럽 BE 2기 - 클린코드 / 테스트코드 발자국 4주차

강의 출처 Practical Testing: 실용적인 테스트 가이드 학습 내용레이어드 아키텍쳐(Layered Architecture)와 테스트 - 노션 정리Test DoubleDummy - 아무것도 하지 않는 깡통 객체.Fake - 단순한 형태로 동일한 기능은 수행하나, 프로덕션 초기에는 부족한 객체.Stub - 테스트에서 요청한 것에 대해 미리 준비한 결과를 제공하는 객체. 그 외에는 응답하지 않는다.Spy - stub이면서 호출된 내용을 기록하여 보여줄 수 있는 객체. 일부는 실제 객체처럼 동작하고 일부만 stubbing 할 수 있다.Mock - 행위에 대한 기대를 명세하고, 그에 따라 동작하도록 만들어진 객체.Stub / Mock 의 차이? -> Stub은 상태 검증 / Mock은 행위 검증@Mock, @Spy, @MockBean, @SpyBean, @InjectMocks - 노션 정리BDDMockito - Mockito를 BDD 스타일로 wrap해서 사용.// given Mockito.when(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString())) .thenReturn(true); // BDDMockito given BDDMockito.given(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString())) .willReturn(true);Classicist VS. Mockist진짜 객체로 테스트를 하고 필요한 경우에만 mocking해서 테스트를 하자. (Classicist)외부 시스템의 경우 mocking 처리해서 테스트.하나의 테스트는 하나의 주제만을 가져야 한다. 논리구조(if문, for문..) 같은 경우는 지양하는 것이 좋다. 만약 케이스 확장이 필요하다면 @ParameterizedTest 사용. 테스트 환경의 독립성 보장 - given절에서는 값 넣어줄 때 생성자, builder 사용.테스트 간 독립성 보장 - 두 가지 이상의 테스트가 하나의 자원을 공유할 때 주의해야 한다. 공유 자원(인스턴스)의 여러 시나리오를 테스트 하고 싶을 경우? -> @DynamicTest 사용.Test Fixture각각의 테스트에서 given이 중복되는 경우 @BeforeEach 에 작성할 경우 주의 해야 할 점 -> 각 테스트 입장에서 알지 못해도 테스트 내용을 이해하는데 문제가 없는지 / 수정해도 모든 테스트에 영향을 주지 않는지 고려해야 한다.data.sql 사용 지양. -> 무엇을 테스트하고 있는지 파악하기 어려울 수 있다.테스트 클래스마다 builder를 만들어서 각자 필요한 파라미터만 사용한다. (builder class를 만들어서 한 곳에서 관리하는 것이 오히려 복잡도를 늘어나게 한다.)Test Fixture 클렌징deleteAll()mapping된 테이블을 조회 후 delete 한다. 연관된 테이블을 모두 조회한 후 삭제하기 때문에 시간과 비용이 들 수 있다.테이블의 삭제 순서를 고려해야 될 수 있다.deleteAllInBatch()테이블의 삭제 순서를 고려해야 한다.여러 조건들(외래키 조건..)에 따라 삭제가 되지 않을 수 있다.테스트 환경 통합하기ServiceTest, RepositoryTest@ActiveProfiles("test") @SpringBootTest public abstract class IntegrationTestSupport { @MockBean protected MailSendClient mailSendClient; }ControllerTest@WebMvcTest(controllers = { OrderController.class, ProductController.class }) public abstract class ControllerTestSupport { @Autowired protected MockMvc mockMvc; @Autowired protected ObjectMapper objectMapper; @MockBean protected OrderService orderService; @MockBean protected ProductService productService; }private 메서드의 테스트는 하지 말아야 한다. 꼭 해야 된다면 따로 객체를 분리해서 테스트를 할 수 있다.테스트에서만 필요한 메서드는 만들어도 되지만, 보수적으로 접근해야 한다. 미션미션 1 - Layered Architecture 구조의 레이어별 특징과 테스트 작성법 -> 노션 정리미션 2 - @Mock, @Spy, @MockBean, @SpyBean, @InjectMocks 차이점 / @BeforeEach 배치 -> 노션 정리회고인프런 워밍업 클럽 BE 2기 4주차라니 시간이 어떻게 흘러간지 모르겠다. 이번 주는 특히나 내가 평소 궁금했던 것들에 대한 강의여서 더 집중해서 들었던 것 같다. 바로 프로젝트에 적용 해볼 만 한 내용이 많아서 만족스러웠다. 워밍업 클럽 진도를 따라가는게 쉽지는 않았지만 지나고 보니 포기하지 않고 어떻게든 하려고 노력 했던 것이 많은 도움이 된 것 같다.

백엔드인프런워밍업클럽2기테스트

김진수

인프런 워밍업 클럽 2기 백엔드 - 발자국 4주차

인프런 워밍업 클럽 2기 발자국 4주차1. 한 주의 정리드디어 마지막 주차이다. 이번 주차는 Layerd Architecture에서 Presentation Layer와Test Double 그리고 테스트를 작성하기 위한 팁들, 마지막으로 부록이 있다. 마지막 페이즈답게 테스트를 위한 지식공유자님의 개인적인 견해와 팁들이 많이 녹아져 있는 강의들이라 좋았다. ✅ 섹션 6. Presentation Layer Test표현 계층에 대한 테스트를 작성하는 방법에 대해 배움,중요한 것은 비즈니스 로직이 들어가는 것이 아니라 넘겨온 값들에 대한 검증이라고 생각한다고 하더라,나 또한 동의한다. ✅ 섹션 7. Mock을 대하는 자세Test Double에 대해 배우고 각 객체의 사용법 그리고 지식공유자님의 개인적 견해가 들어가 있다. 처음으론 Stub과 Mock! 많이 헷갈렸는데Stub은 상태 검증Mock은 행위 검증이라는 관점에서 접근하는 방법을 배웠다. 다음은 Mock하면 항상 나오는 말인데, Classicist VS Mockist이다. 우선 나는 Classicist쪽에 더 가깝다. Mocking을 하면 항상 통과할텐데..(왜냐면 그렇게 짜여지니까)실제상황에서의 다양한 변인들을 통제할 수 있을까? 하는 생각이다. 그렇지만 완고한 고전파는 아니고 Mocking하고 넘어가도 되는 부분은 충분히 그럴 수 있다는 생각이다. ✅ 섹션 8. 더 나은 테스트를 작성하기 위한 구체적 조언완전 농축 액기스 섹션이다.지식공유자님께서 여지껏 겪어오면서 고민하고, 또 좋았던 경험을 바탕으로 팁들을 녹여놓은 섹션이다.다른 섹션들도 물론 군데군데 그것들이 녹여져있지만, 이 섹션에서는 아예 그냥 키워드를 퍼먹여준다.꼭꼭 씹고 내 것으로 만들자. ✅ 섹션 9. Appendix부록인데 부록이 아니다.우선 처음은 테스트 코드를 조금 친숙히 다가가는 법, 아닌 말로 뭐 만드는게 없는데 테스트코드를 어떻게 짜요? 란 생각이 은연 중에 있었다.그런 나의 썩은 정신 상태를 고쳐줄 수 있는 좋은 방법이었다. Spring REST Docs는 확실히 Swagger와는 다른 장점을 보인다.나는 Docs쪽을 더 선호하는 데 이 강의에서 말한 Swagger의 단점이 나는 아주 치명적으로 느껴져서이다. ✅ 섹션 10. Outro그 동안 학습했던 것들에 대한 정리와 조언..? 사람들은 매번 겪어야 깨닫는 특성이 있는데.나 또한 마찬가지고, 어찌됐든 테스트를 짜는게 느린게 아니라 빠른거다 라는 것은 점점 피부로 느껴진다. 흔히 나는 게임에 비유를 하는데 테스트 코드는 공략이다. 이 요구사항을 어떻게 해치울 지 공략이 있다면, 프로덕션 코드는 공략대로 가면 된다. 근데 공략이 없다면.. 좀 더 오래걸리더라 ..  2. 미션이번 주차에서는 Layerd Architecture 구조의 레이어 별 특징과 어떻게 테스트하면 좋을 지 그리고 @Mock, @MockBean, @Spy, @SpyBean, @InjectMock에 대한 정리와예시 테스트의 시나리오 재배치 2가지의 미션이 있었다. 하나하나 작성하기 양이 좀 되어 따로 블로그에 작성한 링크를 참조하려 한다. ✅ 미션 Day-15https://romanc3.tistory.com/131 ✅ 미션 Day-18https://romanc3.tistory.com/132 🤔 내 생각을 정리하자면강의도 좋았지만, 워밍업 클럽 자체가 좋은 기획 같다.동일한 관심사를 가진 사람들과 같은 강의를 보며 다른 생각을 경험할 수 있다는 점이 아주 좋았고,지식 공유자님과 면대면은 아니더라도 의견을 주고 받을 수 있는 공간을 제공 받을 수 있다는 것이 큰 이득으로 다가왔다. 잘하고 싶다면, 잘하는 사람을 모방 하라는 말이 있다.모방을 우습게 보는데.. 따라하기란 쉬운게 아니다. 결국 똑같이 따라할 수 있다는 것은 똑같은 실력이란 것이다.그러한 관점에서 나는 내가 생각하기에 좋은 개발자 분들을 많이 알 수 있게 된 기회였다. 언제까지나 테스트에 매몰되어 있지는 말고, 얼른 마무리해서 습관적으로 테스트를 작성하고 또 다른 부분을 신경쓸 수 있는 개발자로 거듭나길 연습해야겠다 😃

백엔드백엔드테스트

하양이

워밍업 클럽 2기 BE 클린코드&테스트 발자국 4주차

Day 15. Spring & JPA 기반 테스트: Presentation LayerPresentation Layer외부 세계의 요청을 가장 먼저 받는 계층파라미터에 대한 최소한의 검증을 수행한다.MockMvcMock(가짜) 객체를 사용해 스프링 MVC 동작을 재현할 수 있는 테스트 프레임워크미션 - 생각하는 레이어별 특징과 테스트 방법Persistence Layer데이터 저장 및 조회를 담당데이터베이스에 연결하여 데이터 저장 및 조회가 잘 되는지 테스트Business Layer비즈니스 로직을 담당비즈니스 규칙에 맞게 올바르게 동작하는지 테스트Presentation Layer사용자와 상호작용을 담당사용자가 보낸 요청의 유효성 체크와 응답이 제대로 가는지 테스트Day 16. Mock을 마주하는 자세Test Double상태 검증 -> Stub행위 검증 -> Mock@Mock, @Spy, @InjectMocks@Mock : Mock 객체로 만듬@InjectMocks : Mock 객체를 주입해줌@Spy : 일부만 Mock 객체로 만듬BDDMockitoMockito와 동일하다.BDD 스타일로 이름만 변환.Mockito.when().thenReturn(); BDDMockito.given().willReturn();Day 17. 더 나은 테스트를 작성하기 위한 구체적 조언한 문단에 한 주제!: 하나의 테스트 코드에서 하나의 테스트만!완벽하게 제어하기: 제어 불가능한 영역은 상위 계층으로!테스트 환경의 독립성을 보장하자테스트 간 독립성을 보장하자한 눈에 들어오는 Test Fixture 구성하기: given 절을 구성할 때의 주의사항Test Fixture 클렌징테스트 수행도 비용이다. 환경 통합하기Q. private 메서드의 테스트는 어떻게 하나요?해서도 안 되고 할 필요가 없다.Q. 테스트에서만 필요한 메서드가 생겼는데 프로덕션 코드에서는 필요 없다면?만들어도 되지만 보수적으로 접근하기!Day 18. 학습 테스트 | REST Docs학습 테스트잘 모르는 기능, 라이브러리, 프레임워크를 학습하기 위해 작성하는 테스트Spring REST Docs테스트 코드를 통한 API 문서 자동화 도구Spring REST Docs : https://docs.spring.io/spring-restdocs/docs/current/reference/htmlsingle/Asciidoctor : https://asciidoctor.org/Swagger : https://swagger.io/미션 - @Mock, @MockBean, @Spy, @InjectMocks의 차이 정리@Mock: 해당 객체를 Mock 객체로 만든다.@MockBean: Spring의 ApplicationContext에 Mock 객체로 만들어 빈으로 등록한다.@Spy: 일부분만 Mock 객체로 만들어준다.@InjectMockes: Mock 객체로 만들어 주입해준다.미션 - 각 항목을 @BeforeEach, given절, when절 배치@BeforeEach void setUp() { 1-1., 2-1., 3-1. 사용자 생성에 필요한 내용 준비 1-2., 2-2., 3-2. 사용자 생성 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-3. 게시물 생성에 필요한 내용 준비 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 }회고아기다리 고기다리던 금요일 특강을 회사일때문에 참가하지 못했다.하필 저번주도 다음주도 아닌 이번주 금요일에 하필...아쉽지만 지금까지 공부하고 배운 내용을 내것으로 만들어 가야겠다.출처https://inf.run/zgJk5https://inf.run/kHiWM

백엔드워밍업클럽테스트

gotjd9773

[인프런 워밍업 클럽 스터디 2기 백엔드] 4주차 발자국

개요4주차 종료!Practical Testing 실용적인 테스팅 가이드를 완강 했다!인프런 워밍업 클럽 스터디 2기 백엔드 과정... 이것으로 끝!감격스럽다.4주차 공부한 내용권장 진도표에 맞게 진도를 나갔네? 배운 것들1. MockitoMockito 라이브러리를 써봤지만, 사용할 때마다 찝찝한 느낌을 갖고 사용해왔다.이번 주차에 강의를 학습하며 Mockito를 언제 쓰면 좋은지 @MockBean 과 @Mock 의 차이는 무엇인지를 제대로 알 수 있었다. 2. Classicist vs Mockist우빈님은 Classicist 인데, 강의를 들어보니 나도 Classicist가 되었다.정답이 있는 문제는 아니라 상황에 맞게 적절히 Mocking 할 땐 하고, 통합 테스트할 땐 하고 하면 될 듯 하다. 3. Test Fixture 가이드라인다른 강의에서 Fixture를 하나의 클래스로 관리하라고 배웠었다.그래서 그렇게 사용해왔는데, 문제는 원하는 필드를 지정해주고 싶을 때마다 Fixture를 생성하는 메서드가 증가하게 되고,메서드가 증가하면 관리가 너무 어려워지곤 했다. 더군다나 큰 프로젝트 같은 경우 엔티티당 필드가 수 십개가 넘어가는 게 대부분 인데, 이걸 전부 하나의 클래스로 관리하는 건 별로 좋은 방법 같지는 않다.  강의를 통해서 Test Fixture를 어떻게 생성하는 지, 어떻게 생성 메서드를 관리하는 지 배울 수 있었다.  4. 테스트 환경 통합하기테스트 환경을 통합해야 한다는 개념 자체를 몰랐다. 이런 게 가능할 거라 생각도 못했던 것 같다. 강의 들으면서 조금 충격을 받았다. 5. private 메서드를 테스트하고 싶은가? 그러면 책임 분리를 고민해봐라이것도 충격! private 메서드를 테스트하지 말라고 하시는 말씀에"그렇구나, 테스트 안 해도 되네? 개꿀!" 이렇게 생각하며 설렁설렁 듣고 있었는데,private 메서드를 새로운 객체에 public 메서드로 빼놓고 객체간 협력하게 하는 코드를 작성하시는 모습이 인상적이었다.테스트 생각을 많이 하다 보면 자연스레 객체지향에 가까워질 수도 있음을 깨달았다. 6. 학습테스트프로젝트에 쓰고 싶은 새로운 라이브러리를 테스트로 학습하는 건 정말 좋은 방법인 것 같다. 7. Spring REST docsSwagger만 사용해봤는데 Spring REST docs는 들어는 봤지, 이번에 처음 사용해봤다.설정하는 게 어렵긴 한데, 실무에서 많이 쓰인다고 하니 이번에 경험해볼 수 있어서 좋았다. 미션이번 주차에는 Day 15. 미션, Day 18. 미션이 있었다. Day 15. 미션 - Layered Test 작성법 자기만의 언어로 정리하기배운 내용을 다시 한 번 정리하는 거라 어렵진 않았다.https://zircon-neptune-a7d.notion.site/Day-15-Layered-test-124ba1f1340980ddb599f68747a2ddfe?pvs=4 Day 18. 미션 Day 18. 미션 - 1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks의 차이 정리하기역시 배운 내용을 다시 한 번 정리하는 거라 어렵진 않았다.https://zircon-neptune-a7d.notion.site/Day-18-129ba1f134098015983ade0586420ed1?pvs=4 Day 18. 미션 - 2. 수도 코드로 작성된 테스트 3개의 코드를 재배치하기제시된 수도 코드@BeforeEach void setUp() { ❓ } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { 1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 1-5. 댓글 생성에 필요한 내용 준비 1-6. 댓글 생성 // given ❓ // when ❓ // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { 2-1. 사용자 생성에 필요한 내용 준비 2-2. 사용자 생성 2-3. 게시물 생성에 필요한 내용 준비 2-4. 게시물 생성 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 2-7. 댓글 수정 // given ❓ // when ❓ // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { 3-1. 사용자1 생성에 필요한 내용 준비 3-2. 사용자1 생성 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 3-9. 사용자2가 사용자1의 댓글 수정 시도 // given ❓ // when ❓ // then 검증 }제시된 수도 코드는 중복이 많아 보인다. 깔끔하게 정리해보는 미션이었다.내가 재배치한 결과는 아래와 같다.@BeforeEach void setUp() { 1-1. 사용자 생성에 필요한 내용 준비 1-2. 사용자 생성 1-3. 게시물 생성에 필요한 내용 준비 1-4. 게시물 생성 } @DisplayName("사용자가 댓글을 작성할 수 있다.") @Test void writeComment() { // given 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then 검증 } @DisplayName("사용자가 댓글을 수정할 수 있다.") @Test void updateComment() { // given 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName("자신이 작성한 댓글이 아니면 수정할 수 없다.") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when & then --> 예외 발생 3-9. 사용자2가 사용자1의 댓글 수정 시도 } 끝! 4주간 알차게 학습했다.미션과 발자국, 두 개 강의 모두 100% 학습해서 뿌듯하다.인프런 워밍업 클럽 스터디 GOOD!  

백엔드테스트Junit5MockitoSpringRestDocs

wisehero

[인프런-워밍업클럽 BE 2기] Day18 과제

1. @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks 의 차이를 한번 정리해 봅시다. 모두 JUnit, Spring 테스트 환경에서 사용된다. 각각의 어노테이션들은 그 목적과 사용 방식이 조금은 다르다. @Mock가짜 클래스 객체를 생성한다. 이 어노테이션에 의해 모킹된 객체는 실제 객체의 메소드 호출에 대해 빈 응답을 준다.외부 의존성을 최소화 해줄 수 있어서 단위 테스트를 작성할 때 유용하다. 실제 객체의 메소드를 호출하지 않으니당연히 실체 객체를 생성하는 것도 아니다. @MockBeanSpringBoot에서 제공하는 어노테이션이고 Spring 애플리케이션의 컨텍스트에서 관리하는 빈을 모킹한다.@Mock은 스프링 컨텍스트와 관련이 없지만 @MockBean은 스프링 컨텍스트와 관련이 있다. 특정 빈을 모킹된 객체로대체할 때 사용된다. 주로 통합 테스트에서 다른 빈과의 의존성을 모킹할 때 유용하다. @Spy스파이 객체는 실제 객체의 메소드 호출을 그대로 유지한다. 특정 메소드를 모킹할 수 있는데 일부 메소드는 실제로 호출되게하고일부 메소드는 모킹할 수 있다.  @SpyBean@MockBean과 마찬가지로 스프링 애플리케이션 컨텍스트에서 관리하는 빈을 스파이한다. @InjectMocksInject라는 말에서 알 수 있듯이 의존성 주입을 도와주는 어노테이션이다. @Mock이나 @Spy를 명시한 클래스들을@InjectMocks라는 어노테이션이 달린 대상 클래스에 의존성을 주입해준다. 주로 단위테스트에서 사용된다.  "@BeforeEach void setUp() { 1-1. 사용자1 생성에 필요한 내용 준비 1-2. 사용자1 생성 3-5. 사용자1의 게시물 생성에 필요한 내용 준비 3-6. 사용자1의 게시물 생성 } @DisplayName(""사용자가 댓글을 작성할 수 있다."") @Test void writeComment() { // given 1-5. 댓글 생성에 필요한 내용 준비 // when 1-6. 댓글 생성 // then 검증 } @DisplayName(""사용자가 댓글을 수정할 수 있다."") @Test void updateComment() { // given 2-5. 댓글 생성에 필요한 내용 준비 2-6. 댓글 생성 // when 2-7. 댓글 수정 // then 검증 } @DisplayName(""자신이 작성한 댓글이 아니면 수정할 수 없다."") @Test void cannotUpdateCommentWhenUserIsNotWriter() { // given 3-3. 사용자2 생성에 필요한 내용 준비 3-4. 사용자2 생성 3-7. 사용자1의 댓글 생성에 필요한 내용 준비 3-8. 사용자1의 댓글 생성 // when 3-9. 사용자2가 사용자1의 댓글 수정 시도 // then 검증 }" 

백엔드백엔드워밍업클럽클린코드테스트

sdsd988

Layered Architecture 구조의 테스트 작성 방법

인프런 워밍업 클럽 백엔드 2기 클린코드, 테스트 코드 참여 미션 수행 중 하나입니다!관련 강의 :Practical Testing: 실용적인 테스트 가이드( https://www.inflearn.com/course/practical-testing-%EC%8B%A4%EC%9A%A9%EC%A0%81%EC%9D%B8-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EA%B0%80%EC%9D%B4%EB%93%9C/dashboard)1. Layered Architecture ? 소프트웨어 개발 방법 중 하나로, 계층(Layer) 의 수에 따라 N-tier Architecture 부르기도 한다.계층은 어떻게 나누는 것인가? - 책임에 따라서 나눈다.강의에서는 3-tier Architecture 기준으로 나누었다. (Persistence, Business, Prsentation) 2. Layer(Persistence, Business, Prsentation) 1. Persistence Layer  책임 : 도메인(객체)의 생성과 검증 도메인의 생성과 관련된 책임을 가진 계층이다.애플리케이션에서 생성한 객체(Domain)이 데이터베이스에 올바르게 저장되는지 검증하는 과정이 필요하다. Persistent Layer 는 객체가 어떻게 저장되고, 어떤 파라미터를 필요로하는 지 이해할 수 있는 계층이다.테스트 코드 작성을 통해, Business 계층에서 사용될 객체들에 대해 이해를 가질 수 있는 계층이라 생각한다.뒤에 올 Business, Presentation 계층의 작성을 위한 기본적인 토대를 제공하는 계층이다.따라서, 이어질 계층에서 도메인에 대한 고민을 할 필요 없도록 테스트 코드를 작성해주는 것이 필요하다고 생각한다. 2. Business Layer 책임 : 도메인의 비지니스 로직 수행 객체의 생성과 검증이 완료된 토대에서, 서비스의 로직 을 수행하는 책임을 가진 계층이다.Persistent Layer에서 검증되고, 생성된 객체가 수행하는 책임을 검증하는 계층이라고 볼 수 있다.그렇기에, 코드의 양이 많고 테스트 코드 작성도 복잡해진다.Service(Business)은 Persistent(Repository) 의존한다. 즉 2개의 계층이 테스트에 필요해진다.중요하다고 생각하는 지점은, 이 계층은 비지니스 로직 에 집중해야 하는 계층이라는 점이다.객체의 생성과 관련된 코드는 감추고 , 로직과 관련된 코드는 표현되어야 한다.강의를 들으면서, 책임을 어떻게 분리할 것인가? 라는 의문이 생길 수 있다고 생각했다.비지니스 계층을 작성하면서, 도메인과 비지니스 그리고 로직과 로직 사이의 리팩토링이 많이 이루어 질 수 있다고 생각!  3. Presentation Layer책임 : 생성과 로직이 처리된 데이터의 출력 2 계층에서 생성되고, 처리된 데이터가 올바르게 생성되거나 프런트엔드에 올바르게 반환되는지 확인하는 책임을 가진 계층Business 계층에 의존한다. Business Layer 테스트에서 주의해야 할 점과 같이, Presentation Layer 검증에 집중해야 한다.하지만, Business Layer의 특징은 복잡하다는 것이 있었다. 대체(Mock)개념의 필요성Presentation Layer 계층의 테스트에 집중하기 위해 Mockito 를 활용하여, 가짜 객체를 생성하고 테스트에 도입한다.결국 데이터의 바인딩(Binding), 맵핑(Mapping) 에 집중해야 한다.API를 호출하면, 의도된 매개 변수를 받고 올바른 응답을 생성하는 과정을 검증할 수 있어야 한다.  

백엔드백엔드인프런워밍업클럽테스트스프링레이어드아키텍쳐

whffkaos007

워밍업 클럽 2기 BE 클린코드&테스트 : 미션 - Day 15

 이 글은 박우빈님의 강의를 참조하여 작성한 글입니다. 미션 - Day 15 미션 내용Layered Architecture 구조의 레이어별 테스트 작성법을 알아보았습니다. 레이어별로 1) 어떤 특징이 있고, 2) 어떻게 테스트를 하면 좋을지, 자기만의 언어로 다시 한번 정리해 볼까요? 1. 계층별 특칭 Layered Architecture : Presentation Layer <-> Business Layer <-> Persistence Layer Layered Architecture 는 3가지 계층으로 구성된다.웹 클라이언트와 연결된 Controller 부분에 해당하는 Presentation Layer, 서비스의 비즈니스 로직을 처리하는 Business Layer, DAO에 해당하는 Persistence Layer가 있다. 이렇게 계층을 나누는 이유는 관심사의 분리이다. 관심사, 책임을 나누기에 테스트의 작성을 편리하게 하고 신뢰성을 높이고 유지보수 또한 수월하다.  Presentation Layer외부 세계의 요청을 가장 먼저 받는 계층파라미터에 대한 최소한의 검증을 수행한다. Business Layer비즈니스 로직을 구현하는 역할Persistence Layer와의 상호작용(Data를 읽고 쓰는 행위)을 통해 비즈니스 로직을 전개시킨다.트랜잭션을 보장해야 한다. Persistence LayerData Access의 역할비즈니스 가공 로직이 포함되어서는 안 된다. Data에 대한 CRUD에만 집중한 레이어   2. 어떻게 테스트를 하면 좋을지, 자기만의 언어로 다시 한번 정리해 볼까요? 하나의 모듈을 기준으로 독립적으로 진행되는 단위 테스트와 둘 이상의 여려 모듈이 협력하여 기능을 통합적으로 검증하는 통합 테스트가 있다.각 계층에 대한 테스트는 다음과 같이 진행하면 좋을 거 같다. Persistance Layer -> Spring과 통합한 단독 계층 테스트(Spring, Jpa 등 활용한 DB 접근), 단위 테스트 성격 Business Layer -> Persistence를 포함한 통합 테스트 Presentation Layer -> 이외 계층을 Mocking한 단독 계층 테스트, 단위 테스트 성격 강사님의 의견과 유사한 생각을 가지고 있다. 위와 같은 생각은 다음과 같은 이유 때문이다. 이유Persistence Layer는 DAO 관련 계층이다. 컨트롤러나 서비스 등 이외 계층과 협력할 필요가 없다. 그렇기에 스프링, JPA를 활용한 테스트를 진행할 수 밖에 없다. A와 B 기능이 각각 있을 때, 정상적으로 동작할 수 있다. 하지만 A + B 와 같이 사용된다면 실제 결과는 어떻게 나올지 모른다. 이러한 여러 모듈이 복잡하게 상호작용할 수록 이를 예측하는 건 더 어렵다. 이처럼 Business Layer 와 Persistence Layer를 통합한 테스트를 진행하면 더 높은 신뢰성을 보장할 수 있다.또한 Persistence Layer에 대한 테스트를 이미 작성했다면 굳이 Persistence Layer를 Mocking하지 않는 것이 더 비용적으로 합리적일 수 있다. Presentation Layer는 외부 세계와 연결된 계층이다. 외부 세계로 받은 정보에 대한 검증이 필요하다.도메인의 성격, 서비스에 대한 내용과는 무관하다. 따라서 굳이 도메인 관련 로직을 검증할 필요는 없다고 생각한다.물론 각 모듈이 상호작용할 때와 각각 작용할 때는 다른 결과값이 나올 수 있기에 3가지 계층에 대한 검증을 한 번에 하는 것이 더 신뢰성을 보장할 것이다.그렇지만 비용 또한 고려해야 하므로 수동 테스트로 마무리하거나 비용이 나오더라도 꼭 검증해야할 정도로 중요하다면 그때 모든 계층에 대한 통합 테스트를 작성하여 신뢰성을 보장하면 된다고 생각한다.    

백엔드테스트Layered-Architecture

Practical Testing 3주차 발자국

서문테스트에 대해서는 늘 많은 고민이 있었다.테스트를 작성하다보니 많은 선택지들이 있었는데 이번 3주차 간의 강의를 통해서 이전에 수강했던 강의를 복습하는 차원에서 다시 한 번 바라보았다.특히나 처음에 강의를 들었을 경우에 가장 와닿고 도움이 많이 되었던 말은 테스트 코드는 좋은 구조를 설계해나가는 과정이라는 것이다.테스트를 작성해나가다 보면 내가 짜놓은 코드의 설계가 확장성 있게 작성이 되지는 않았는지, BDD 기반으로 테스트 코드를 작성해 나가면서 내가 짠 메서드의 행위가 테스트 하기 쉽도록 작성되어 있는지에 대해서 쉽게 파악 할 수 있었다.취업 전에 이 강의를 보고 난 이후의 경험과 현재 취업을 하고 나서 여러가지 테스트 서적을 보고 난 이후의 경험이 합쳐져서 더 많은 도움이 되고는 한다.단위 테스트기존에는 단위 테스트의 기준을 항상 비즈니스 레이어 기준으로 잡았었다. 단위 테스트는 책 한권으로 다룰 만큼 되게 폭 넓은 분야인데 그렇게 넓게 다룰 필요가 있는가? 라고 생각을 하기도 하였다.하지만, Effective Software Testing 책에서 읽어 본 바로는 하나의 계층만 테스트 할 수 있는 구조라면 단위 테스트이다.라는 말이 나의 모호함을 해결해주었다. 다른 말로, 통합 테스트와 단위 테스트의 기준은 무엇을 바라보아야 하지? 라고 했을 때, 다른 계층과의 결합이 생기는 순간 이는 통합 테스트를 바라보면 된다는 것이다.이 관점에서 통합 테스트를 작성 할 때 Mocking 하는 것을 더 생각해 볼 필요가 있다. Mock은 주어진 행위에 대한 결과가 내가 예측한 값을 사용하게 된다. 이는, 실제로 그 값이 내려오지 않을 수 있음을 시사하는데 이로써 해당 계층에 대한 테스트가 신뢰도 있는 테스트가 작성되지 않는다는 것이다.따라서, Mock을 사용한 테스트를 하게 되면 이는 단위 테스트를 작성하는 형태가 된다. 내 계층에서 어떠한 메서드가 이 값을 받았을 때 해당 계층의 결과는 이 결과가 나와야 해. 라는 의미를 가지게 되는 것이다.프레젠테이션 레이어이 부분은 강의를 보면서도 아직 고민이 많다.우리는 프레젠테이션 레이어 테스트를 작성하면서 강의에서도 컨트롤러 영역에서의 서비스 계층 영역을 mocking 하여 결과 값을 가지고 오는 것을 볼 수 있다. 물론 전제는 서비스가 테스트되었기 때문에 서비스 계층에서의 결과 값은 예측 값이 맞겠지만, 이는 서비스 영역에서 결과 값이 필드가 바뀌는 경우에 놓칠 수 있는 경우를 시사하게 된다.물론 이 부분은 개발자가 신경써야 하는 부분이기도 하지만 휴먼 에러를 방치하는 것은 또 좋지 않다고 생각을 하긴 한다. 이 방법을 해결하기 위해서는 결국 E2E (End-To-End) 테스트를 진행하기 위해서 assured 테스트를 사용해보기도 하였는데, 이럴 경우에 Persistent 레이어까지 전부 test container를 띄우면서 실 상황과 유사한 상황으로 테스트를 진행하다보니 테스트에 많은 시간이 소요되게 된다.물론, 우빈님이 소개해주신 스프링 부트 컨테이너의 빈 목록을 한데 모아서 관리한다면 속도 개선은 많은 부분 이루어지지만, 그 이전에 테스트를 실행 할 때마다 해당 테스트에 필요한 데이터들을 새로이 만들어주는 과정이 많은 시간을 잡게 되고, 이는 결국 비즈니스 개발에 많은 시간을 잡아먹게 된다.추가적으로, E2E로 작성하게 되는 경우에 나타나는 문제점은 어찌됐든 서비스 영역의 테스트 결과 값이 서비스 계층의 비즈니스가 완성되기전까지 문서화를 위하여 Dummy 형태의 응답 값을 가지게 된다는 것이다.이러한 여러가지 상황 속에서 아직까지 나만의 답을 찾지 못하였으니 계속 경험을 가지면서 적절한 나만의 기준을 찾는 것이 좋을 것 같다. 해당 내용에 대해서는 우빈님께 질문을 드릴 예정이다.영속성 레이어이 부분도 많은 고민을 가지고 있었다. 취업 준비를 할 때에는 H2 인메모리 DB를 사용하여 많은 부분 영속성 레이어의 테스트를 구성 할 수 있었으나, 실제로 현업에 왔을 때에는 H2에서는 정상 동작하나 실제 DB에서는 작성하지 않는 상황들이 적지 않게 발생하는 것을 볼 수 있었다. 이를 대체 할 방법이 Test Container를 띄워서 테스트를 작성하는 것인데, 시간이 생각보다 오래 걸린다. 아직 이 부분도 해결이 되지 않은 것 같다. 우빈님 강의 뿐만이 아니라 더 많은 서적들을 보면서 영속성 계층을 어떻게 처리하는게 좋을지 이 부분도 경험치를 쌓아나가야 하는 것 같다.모든 상황에서는 은탄환은 존재하지 않는다. 실제로 어떻게 하는지 지금 내 레벨에서는 최대한 카피하여 많은 경험치를 쌓아가는 과정이 중요하다고 생각한다. 또 좋은 기술이 나오지 않을까? 라는 생각이 들기도 한다.마무리옛날에는 테스트를 짜는데 시간이 오래걸린다는 말이 어느정도 맞는 말이라고 생각한다. 하지만, 현재에는 기술이 너무 좋아졌다. copilot을 사용하면서 테스트를 짜는 시간을 거의 300%는 더 빠르게 작성 할 수 있게 해주는 것 같다.기술을 적절히 활용하면서 회사 내에 테스트를 짜는 문화를 좀 더 거부감 없게 만들어나가고 싶다.

소프트웨어 테스트테스트단위테스트회고

zooxop

인프런 워밍업 스터디 클럽 2기 백엔드(클린코드&테스트코드) 발자국 - 3주차

인프런 워밍업 클럽 2기, 백엔드(클린코드&테스트코드) 과정에 참여하고 있습니다.이번 3주차에는 테스트에 대한 이론적인 내용과 TDD, 실용적인 테스트 방법등을 학습했습니다.강의 링크: Readable Code: 읽기 좋은 코드를 작성하는 사고법 [학습 요약] 테스트의 필요성왜 작성해야 할까?사람이 수동으로 직접 테스트하는 데에는 한계가 있다.테스트 코드 작성을 통해 얻는 이점빠른 피드백자동화안정감테스트 코드를 작성하지 않는다면..변화가 생기는 매순간마다 발생할 수 있는 모든 Case를 고려해야 한다.변화가 생기는 매순간마다 모든 팀원이 동일한 고민을 해야한다.빠르게 변화하는 소프트웨어의 안정성을 보장할 수 없다.테스트 코드가 병목이 된다면..프로덕션 코드의 안정성을 제공하기 힘들어진다.테스트 코드 자체가 유지보수하기 어려운, 새로운 짐이 된다.잘못된 검증이 이루어질 가능성이 생긴다.올바른 테스트 코드는,자동화 테스트로 비교적 빠른 시간 안에 버그를 발견할 수 있고, 수동 테스트에 드는 비용을 크게 절약할 수 있다.소프트웨어의 빠른 변화를 지원한다.팀원들의 집단 지성을 팀 차원의 이익으로 승격시킨다.가까이 보면 느리지만, 멀리 보면 가장 빠르다.테스트는 귀찮다. 귀찮지만, 해야한다! 단위 테스트작은 코드 단위를 독립적으로 검증하는 테스트작은 코드: 클래스 or 메서드검증 속도가 빠르고, 안정적이다.외부에 의존을 하지 않기 때문에JUnit5단위 테스트를 위한 테스트 프레임워크XUnit - Kent BeckSUnit(SmallTalk), JUnit(Java), NUnit(.NET), DUnit(Delphi)AssertJ테스트 코드 작성을 원할하게 돕는 테스트 라이브러리풍부한 API, 메서드 체이닝 지원테스트 케이스 세분화하기항상 질문하기: 암묵적이거나, 아직 드러나지 않은 요구사항이 있는가?해피 케이스와 예외 테스트를 도출해낼 수 있어야 한다.경계값 테스트경계값?: 범위(이상, 이하, 초과, 미만), 구간, 날짜 등테스트하기 어려운 영역을 구분하고 분리하기테스트하기 어려운 영역을 갖고 있는 코드가 추가된다면, <u>전체 테스트가 망가질 가능성</u>이 생긴다.예시)LocalDateTime.now() 를 사용하는 기능을 테스트할 때, 테스트를 실행하는 시간에 따라 성공할수도, 실패할수도 있게 됨.이 때, LocalDateTime.now() 를 사용하는 코드가 곧 테스트하기 어려운 영역이 된다.이 때, 테스트가 어려운 영역을 외부에서 주입받도록 변경하면 테스트 하기 수월해진다.외부로 분리할수록, 테스트 가능한 코드는 많아진다.테스트하기 어려운 영역 코드 예시관측할 때마다 다른 값에 의존하는 코드현재 날짜/시간, 랜덤 값, 전역 변수/함수, 사용자 입력 등외부 세계에 영향을 주는 코드표준 출력, 메시지 발송, 데이터베이스에 기록하기 등테스트하기 쉬운 영역 코드 예시순수 함수같은 입력에는 항상 같은 결과 반환외부 세상과 단절된 형태 (전역 변수를 변경하지 않는) TDD프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현 과정을 주도하도록 하는 방법론[Red - Green - Refactor] 3단계 구조로 순환하며 진행Red: 실패하는 테스트 작성의도적으로 실패하게 테스트를 작성하라는게 아니다.도메인적 지식을 기반으로, 테스트가 통과해야만 하는 조건으로 테스트 코드를 작성하라는 의미.ex) 테스트에서는 10 이라는 값이 나올것을 기대하지만, 구현이 미완성이라서 0이 리턴되는 경우에 기대값을 변경하지 않고 그대로 두는 것을 말한다.Green: 테스트 통과, 최소한의 코딩최대한 빠르게 테스트 통과만을 위한 코딩을 수행.TDD 방법론에서는 하드코딩도 허용.Refactor: 구현 코드 개선, 테스트 통과 유지구현부 코드를 변경한 다음에도 테스트가 통과 된다 -> 구현이 올바르게 되었다 라고 판단할 근거가 된다.피드백TDD가 제공하는 핵심 가치테스트 코드를 통해 내가 구현한 프로덕션 코드에 대해서 자주, 빠르게 피드백을 받을 수 있다.기능 구현 후 테스트 작성 vs. 테스트 작성 후 기능 구현선 기능 구현, 후 테스트 작성 케이스테스트 자체의 누락 가능성특정 테스트 케이스(해피 케이스)만을 검증할 가능성잘못된 구현을 다소 늦게 발견할 가능성선 테스트 작성, 후 기능 구현복잡도가 낮은, 테스트 가능한 코드로 구현할 수 있게 한다.복잡도가 낮다?: 유연하고, 유지보수하기 쉽다쉽게 발견하기 어려운 엣지(Edge) 케이스를 놓치지 않게 해준다.구현에 대한 빠른 피드백을 받을 수 있다.과감한 리팩토링이 가능해진다.TDD: 관점의 변화TDD 이전의 관점: 테스트는 구현부 검증을 위한 보조 수단TDD 이후의 관점: 테스트와 상호 작용하며 발전하는 구현부TDD는 클라이언트 관점에서 피드백을 주는 Test Driven 도구이다. 테스트는 "문서"다테스트는 "문서"다. 왜?프로덕션 기능을 설명하는 테스트 코드 문서다양한 테스트 케이스를 통해 프로덕션 코드를 이해하는 시각과 관점을 보완어느 한 사람이 과거에 경험했던 고민의 결과물을 팀 차원으로 승격시켜서, 모두의 자산으로 공유할 수 있다.우리는 항상 팀으로 일한다 DisplayName을 섬세하게명사의 나열보다 문장으로 작성하자테스트 행위에 대한 결과까지 기술하기before: 음료 1개 추가 테스트after: 음료를 1개 추가할 수 있다.도메인 용어를 한층 추상화된 내용을 담기메서드 자체의 관점보다, 도메인 정책관점으로 생각하자.테스트의 현상을 중점으로 기술하지 말 것before: 특정 시간 이전에 주문을 생성하면 실패한다.after: 영업 시작 시간 이전에는 주문을 생성할 수 없다.BDD, Behavior Driven DevelopmentTDD에서 파생된 개발 방법함수 단위의 테스트에 집중하기 보다, 시나리오에 기반한 테스트케이스(TC) 자체에 집중하여 테스트한다.개발자가 아닌 사람이 봐도 이해할 수 있을 정도의 추상화 수준(레벨)을 권장Given / When / ThenGiven: 시나리오 진행에 필요한 모든 준비 과정 (객체, 값, 상태 등)When: 시나리오 행동 진행Then: 시나리오 진행에 대한 결과 명시, 검증 Spring & JPA 기반 테스트 레이어드 아키텍처와 테스트Layered Architecture 는 관심사의 분리를 위해 수행한다!책임을 나누고, 유지보수하기 용이하게 만들자Spring & JPA 기반 애플리케이션에서 일반적으로 사용하는 레이어 구조User <-> [Presentation Layer] <-> [Business Layer] <-> [Persistence Layer] <-> DB통합 테스트여러 모듈이 협력하는 기능을 통합적으로 검증하는 테스트일반적으로 작은 범위의 단위 테스트만으로는 기능 전체의 신뢰성을 보장할 수 없다.풍부한 단위 테스트 & 큰 기능 단위를 검증하는 테스트Spring / JPA 훑어보기스프링은 Library? Framework?라이브러리는 내 코드가 주체가 된다.프레임워크는 말 그대로 이미 프레임이 짜여있고, 그 프레임에 짜맞추는 방식으로 코드를 작성하게 됨.Spring IoC(Inversion of Control)DI(Dependency Injection)AOP(Aspect Oriented Programming)ORM (Object-Relational Mapping)객체 지향 패러다임과 관계형 DB 패러다임의 불일치이전에는 개발자가 객체의 데이터를 한땀한땀 매핑하여 DB에 저장 및 조회 (CRUD)ORM을 사용함으로써 개발자는 단순 작업을 줄이고, 비즈니스 로직에 집중할 수 있다.JPA (Java Persistence API)Java 진영의 ORM 기술 표준인터페이스이고, 여러 구현체가 있지만 보통 Hibernate를 주로 사용한다.반복적인 CRUD SQL을 생성 및 실행해주고, 여러 부가 기능들을 제공한다.편리하지만 쿼리를 직접 작성하지 않기 때문에, 어떤 식으로 쿼리가 만들어지고 실행되는지 명확하게 이해하고 있어야 한다.Spring 진영에서는 JPA를 한번 더 추상화한 Spring Data JPA 제공QueryDSL과 조합하여 많이 사용한다.타입 체크, 동적 쿼리JPA 에서 주로 사용되는 어노테이션들@Entity, @Id, @Column@ManyToOne, @OneToMany, @OneToOne, @ManyToMany@ManyToMany: 일대다 - 다대일 관계로 풀어서 사용한다. [후기]본격적으로 테스트 코드에 대한 학습을 시작한 주간이었다. 개발자로 일을 한지 꽤 오래되었지만 테스트를 작성해본 적이 많지 않아서 테스트를 작성하는것에 언제나 애를 먹었었는데, 기초적이고 이론적인 내용부터 자세히 공부하고 예제로 따라해보니 지금까지 잘 모르고 지금까지 완벽하게 이해하지 못하고 넘어갔었던 내용들을 어느정도 해소할 수 있었던 것 같아 좋았다.

백엔드워밍업클럽백엔드테스트클린코드

Seul Ki Lee

워밍업 클럽 2기 BE 클린코드&테스트 발자국 3주차

강의 : Practical Testing: 실용적인 테스트 가이드테스트의 필요성잘 만든 테스트로 인하여 신뢰성 있는 소프트웨어를 만들 수 있다잘 만든 테스트로 인하여 과감한 수정 및 리팩토링이 가능하다테스트 코드 자체가 문서가 된다자동화 테스트와 JUnit테스트를 만드는 것 자체도 비용이 들기에 사람이 수동으로 하기 보다는 자동화 테스트가 필요함테스트를 빠르고 여러번 실행 가능하도록 하도록 JUnit이 돕는다 테스트 어려운 영역을 분리테스트는 반복가능하며 항상 성공하는 테스트여야 한다시간, 랜덤 등의 성격의 경우 매개변수로 주입하여서 테스트 힘든 부분을 분리하여 테스트가 가능하다TDD실패하는 테스트를 만든다테스트를 성공 시킨다리팩토링아래의 3단계를 짧은 사이클로 가져가면서 점차적으로 개발이 가능하다DisplayName테스트는 요구사항을 잘 드러내는 문서의 역할도 겸하기 때문에 Display name을 잘 지어야 한다~ 테스트가 아닌 문장으로 끝내며 주어, 목적, 결과가 다 드러나도록 기재해야 한다BDDgiven, when, then 3단계에 나눠거의 : Practical Testing: 실용적인 테스트 가이드 테스트의 필요성잘 만든 테스트로 인하여 신뢰성 있는 소프트웨어를 만들 수 있다잘 만든 테스트로 인하여 과감한 수정 및 리팩토링이 가능하다테스트 코드 자체가 문서가 된다자동화 테스트와 JUnit테스트를 만드는 것 자체도 비용이 들기에 사람이 수동으로 하기 보다는 자동화 테스트가 필요함테스트를 빠르고 여러번 실행 가능하도록 하도록 JUnit이 돕는다테스트 어려운 영역을 분리테스트는 반복가능하며 항상 성공하는 테스트여야 한다시간, 랜덤 등의 성격의 경우 매개변수로 주입하여서 테스트 힘든 부분을 분리하여 테스트가 가능하다TDD실패하는 테스트를 만든다테스트를 성공 시킨다리팩토링아래의 3단계를 짧은 사이클로 가져가면서 점차적으로 개발이 가능하다 DisplayName테스트는 요구사항을 잘 드러내는 문서의 역할도 겸하기 때문에 Display name을 잘 지어야 한다~ 테스트가 아닌 문장으로 끝내며 주어, 목적, 결과가 다 드러나도록 기재해야 한다BDDgiven, when, then 3단계에 나눠서 테스트를 작성하도록 한다given테스트에 필요한 객체 및 데이터를 생성한다when테스트하고자 하는 내용을 실행한다thenassertj 단언문을 이용하여 테스트하고자 하는 내용을 확인한다 

백엔드클린코드테스트워밍업클럽2기

김진수

인프런 워밍업 클럽 2기 백엔드 - 발자국 3주차

인프런 워밍업 클럽 2기 발자국 3주차1. 한 주의 정리이번 주차부터는 테스트 코드 학습이 시작됐다.테스트 코드는 뭔가 짜야지 짜야지 하면서, 처음 하려고 하면 뜬 구름 같은..?마치 헬스장을 PT 없이 처음 가는 기분일까..? 아무래도 유튜브나 이런걸 보고 할 순 있지만 뭔가처음가면 런닝머신만 뛰고 오기 부지기수이다.나에게 테스트 코드는 그런 느낌이었다. 혼자서 짜면 굉장히 얇은 층만 건들이다가 마는 것 같은..? 3주차에서는 일단 내가 건들이던 층까지라크게 다를 것은 없었지만 그럼에도 많은 것들을 배웠다. ✅ 섹션 2. 테스트는 왜 필요할까?테스트의 필요성에 대해 먼저 간략히 알려주는 섹션이다.여기서 말씀 주신 것들의 대부분이 공부를 하거나 일을 할 때 테스트 코드가 없는 경우에 느낀 불편함들이 있었다.이 섹션에서는 그러한 불편한 부분들 그리고 테스트 코드 자체로 발생할 수 있는 불편함들에 대해 정리 해주고 있다. ✅ 섹션 3. 단위 테스트가장 쉽게 접근할 수 있고 또 빠르게 테스트를 할 수 있는 단위 테스트에 대해 학습했다.단위 테스트를 작성하는 기법이나 프레임워크 등 그리고 어떤 것들을 테스트해야 하는 지 생각하는 방식 등을 알 수 있어 조금은 테스트에 있어 어색한 나에게 좋은 섹션이었다.특히 테스트하기 어려운 것과 쉬운 것을 구분하고 테스트하기 쉬운 구조로 변경하는 방법이 꽤 도움이 되었다.반면에 테스트하기 쉽게 프로덕트를 변경하는 것이 옳은 것인가? 에 대해 한번 고민하게 되었다 ✅ 섹션 4. Test Driven Development한 동안 엄청나게 많은 사람들을 괴롭힌 TDD이다강의에서 간략한 요약으론 프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현 과정을 주도하도록 하는 방법론RED : 실패하는 테스트 작성GREEN : (빠른 시간 내에) 테스트 통과 최소한의 코딩REFACTOR : 구현 코드 개선 테스트 통과 유지 위와 같이 안내해준다. 이 장에 대해선 좀 모호하다. 나는 TDD를 옹호하고 긍정적인 쪽은 아니다.그러나 테스트 코드는 중요하다고 생각한다. 프로덕트를 먼저 짜든 테스트를 먼저 짜든 중요한 것은 그 본질이라 생각하며나는 그 부분이 요구사항을 만족하며 최대한 꼼꼼한 기능 구현이라고 생각한다. ✅ 섹션 5. 테스트는 [ ] 다괄호 안의 내용을 말하는 것이 강의의 스포일까..? 두루뭉술하게 말하자면테스트 자체도 보기 쉽게 작성을 해야한다는 강의 내용이었다.@DisplayName을 명확히 작성한다든지 gwt나 gw&t 방식으로 구분지어 테스트를 작성하여 보기 쉽게 만들어 주는게 좋지 않을까요? 하는 관점이었다. ✅ 섹션 6. Spring & JPA 기반 테스트쓸 건 많은데 쓰기엔 좀.. 강의 내용을 너무 적나라하게 내보낼까봐 조심스럽다.그리고 나 또한 강의의 내용을 그대로 옮기는 회고를 선호하지 않기에.. 이 장에서는 Layerd Architecture에서 많이 활용되는 방식의 테스트 구조를 설명하고아랫단에서부터 올라가고 있다. 우선 이번 주차에선[6-2] Business Layer까지라 나눠서 작성하기도 애매하고.. 일단은 이 강의의 가장 핵심 부분이지 않나 싶다 섹션 6과 7은 그 밖에도 테스트 상황에서 발생할 수 있는 여러 문제 상황들을 상세하게 재연해주시므로 도움이 많이 되는 장이다. 2. 미션이번 주차에서는 테스트 코드를 작성하는 미션이 진행됐다.코드의 양이 꽤 많으므로 github 링크를 같이 첨부하며 어떤 식으로 접근 했는 지 설명하겠다. https://github.com/ckaanf/readable-code/tree/mission/day-12 ✅ 아래부터 차근 차근처음 테스트가 하나도 없는 코드를 받으면 숨이 턱..왜냐하면 테스트 상황에 대한 구조부터 하나하나 쌓아 올려가야 하기 때문이다.그나마 이 프로젝트는 Spring이 아니었기에 여러 Mock들이나 스프링 Bean에 의해 발생하는 문제는 없어서 다행이었다. 타고타고타고나는 일단 메인 비즈니스 로직에서 메서드를 계속 타고 최하단 까지 내려 가는 것으로 먼저 테스트 코드를 작성했다. 거기서 객체 수준의 테스트가 필요하다고 생각되면 작성을 하였고 또 역으로 그 객체를 사용하는 위치로 가서 테스트 코드를 작성했다. 미션은 테스트 코드 작성두 번째로는 테스트를 위한 프로덕트의 변경은 하지 않았다.그저 내가 생각하기에 필요하다고 생각되는 테스트 케이스는 작성하되 그것이 통과하도록 프로덕트를 변경하진 않았다. 이번 미션은 테스트 코드 작성이지 리팩토링이나 기능의 변경이 아니라고 생각했기 때문이다.그렇기에 실패하는 테스트도 존재하며, 그것은 의도된 것임을 밝힌다 최대한 독립적으로마지막으로는 최대한 독립적으로 짜려고 했다. 서로의 테스트가 서로에게 영향을 주지 않도록, 그리고 프로덕트의 코드의 변경이 테스트의 영향을 주지 않도록,또한 테스트하려고 하는 When 외에 변경을 반영하지 않도록 말이다. 🤔 내 생각을 정리하자면테스트 코드는 분명 중요하다.그러나 테스트 코드는 테스트 코드여야 한다.그 책임을 넘어 프로덕트의 책임까지 침범하거나 그 이상의 권한이 주어져서는 안된다고 생각한다. 이번에 적은 양의 코드지만 테스트를 짜면서 느낀 것은 이 적은 양도 꽤 많은 테스트가 필요한데 프로덕트 코드의 테스트는 얼마나 복잡할까?그리고 그걸 지속가능하게 관리하려면 어떻게 해야할까? 등에 대한 생각을 하게 됐다. 다음 주에는 그런 것을 바탕으로 테스트 코드를 관리하는 방법들이나테스트 코드를 분리하는 방법에 대해 같이 공부하면서 강의를 마무리 해야겠다.

백엔드테스트

gotjd9773

[인프런 워밍업 클럽 스터디 2기 백엔드] 3주차 발자국

개요테스트 코드 학습을 시작했다.Practical Testing : 실용적인 테스트 가이드3주차 공부한 내용수강한 강의 영상은 얼마 안 되는 거 같지만, 러닝 타임이 어마어마하다.확실히 긴 러닝타임의 영상은 힘들다.그래도 공부할만한 내용을 배우고 있다고 되뇌이며 강의를 수강했다. 배운 것들1. TDD 적용하기TDD를 처음 해본 것은 아니다.TDD 주제 책들을 읽은 적도 있고, 직접 해 보기도 했다.TDD를 처음했을 때 깨달은 것은 "단일 클래스의 메소드를 TDD로 개발하는 것은 어렵지 않으나, 여러 계층이 있는 스프링 프로젝트에서 TDD를 적용하는 건 어렵구나. 어떻게 적용하지?" 였다. 강의를 통해서 스프링 프로젝트에서 TDD를 적용하는 방법을 배울 수 있었다. 2. DisplayName을 작성하는 법테스트 메서드의 이름이나, DisplayName을 배웠다.항상 중구난방, 기준도 없이 작성해서 고민이 많았던 내용인데,고민 해결! 3. 재고 차감시 재고가 있는지 두 번 체크하는 이유서비스에서 재고 체크 한 번, 엔티티 객체 안에서 재고 체크 한 번동일한 로직이 두 번 반복해줘야 하는 이유를 배울 수 있었다. 4. 컨트롤러에서 하는 유효성 검증, 서비스에서 하는 유효성 검증유효성 검증을 컨트롤러에서만 하는 게 아니라 계층에 맞는 유효성 검증이 있다는 것을 배웠다.  미션이번 주차에는 Day 12. 미션이 있었다. Day 12. 미션 - 읽기 좋은 코드 강의 예제 코드 단위 테스트 작성하기Readable Code: 읽기 좋은 코드를 작성하는 사고법 강의의 예제 프로젝트로 지뢰찾기와 스터디카페가 있다.둘 중 하나를 선택하여 3개의 클래스, 7개의 단위 테스트를 작성하는 것이었다.나는 스터디카페를 선택하였다.강의에서 배운 내용을 그대로 적용만 하면 되는 미션이라 수월하게 마칠 수 있었다. 마무리다음 주차 부터는 Mocking 에 대해서 배우게 된다.항상 테스트 코드를 작성할 때마다, Mocking 을 사용할 때마다 찝찝함을 느끼곤 했다.이번 기회에 제대로 정리하고 가야겠다.

백엔드읽기좋은코드클린코드워밍업클럽테스트

하양이

워밍업 클럽 2기 BE 클린코드&테스트 발자국 3주차

Day 10. 단위 테스트테스트는 왜 필요할까?빠른 피드백자동화안정감단위 테스트작은 코드 단위(클래스 or 메서드)를 독립적으로 검증하는 테스트검증 속도가 빠르고, 안정적이다.테스트 케이스 세분화하기해피 케이스예외 케이스경계값 테스트테스트하기 어려운 영역을 분리하기테스트하기 어려운 영역관측할 때마다 다른 값에 의존하는 코드외부 세계에 영향을 주는 코드순수 함수같은 입력에는 항상 같은 결과외부 세상과 단절된 형태테스트하기 쉬운 코드Day 11. TDD | 테스트는 [ ] 다TDD: Test Driven Development프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현 과정을 주도하도록 하는 방법론테스트와 상호작용하며 발전하는 구현부클라이언트 관점에서의 피드백을 주는 Test Driven애자일 성명서 : http://agilemanifesto.org/테스트는 [ ] 다[ ]는 강의에서😀우리는 항상 팀으로 일한다DisplayName을 섬세하게도메인 용어를 사용하여 한층 추상화된 내용을 담기테스트의 현상을 중점으로 기술하지 말 것BDD 스타일로 작성하기TDD에서 파생된 개발 방법 Given : 시나리오 진행에 필요한 모든 준비 과정 (객체, 값, 상태 등)When : 시나리오 행동 진행Then : 시나리오 진행에 대한 결과 명시, 검증Day 12. 테스트 코드 적용 미션 https://github.com/japygo/readable-code/commits/mission7-1/회고이름 짓기처럼 DisplayName을 짓는 것도 역시나 고민되고 어렵다.테스트 코드를 굳이 작성해야하나 싶은 테스트를 작성해야 하는지 의문이다.테스트 커버리지 보다는 다양한 예외 케이스들을 제대로 했는지가 중요한 것 같다.Day 13. Spring & JPA 기반 테스트: Persistence Layer레이어드 아키텍처(Layered Architecture)와 테스트풍부한 단위 테스트 & 큰 기능 단위를 검증하는 통합 테스트Library vs FrameworkLibrary: 내 코드가 주체Framework: 이미 동작할 수 있는 환경이 있어 내 코드가 수동적Persistence LayerData Access의 역할비즈니스 가공 로직이 포함되어서는 안 된다. Data에 대한 CRUD에만 집중한 레이어Day 14. Spring & JPA 기반 테스트: Business LayerBusiness Layer비즈니스 로직을 구현하는 역할Persistence Layer와의 상호작용(Data를 읽고 쓰는 행위)을 통해 비즈니스 로직을 전개시킨다.트랜잭션을 보장해야 한다.회고테스트 코드 강의 역시 상상 속의 있던 유니콘을 만나는 기분이었다.중요한 걸 알지만 현업에서 만나볼 수 없어서 감이 전혀 오지 않았는데 어떤 느낌인지 알 수 있었다.열심히 해서 다양한 테스트 케이스를 만나 볼 수 있으면 좋겠다.출처https://inf.run/zgJk5https://inf.run/kHiWM

백엔드워밍업클럽테스트

채널톡 아이콘