[인프런 워밍업 클럽 백엔드 스터디 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<DynamicTest> 형식으로 생성한다.사용 예: 테스트 시나리오가 복잡하고 실행할 테스트 케이스의 수나 조건이 실행 중 결정되는 경우에 유용하다.주요 기능:동적 테스트를 생성하려면 @TestFactory 어노테이션 필수!Stream<DynamicTest>를 반환한다.메서드 내부에서 테스트 케이스와 이름을 동적으로 정의할 수 있습니다. Spring REST DocsAPI의 구조, 기능, 요청 및 응답 형식 등을 문서화AsciiDoc의 도움을 받아 MarkDown문법으로 작성하고 라이브러리를 의존성 주입받아 html로의 변환도 쉽게 할 수 있다.Swagger vs. REST DocsSwagger적용이 쉽다.문서에서 바로 api호출을 수행할 수 있다.프로덕션 코드에 침투적이다.신뢰도가 떨어진다.REST Docs테스트를 통과해야 문서가 만들어지므로 신뢰도가 높다.프로덕션 코드에 비침투적이다.코드의 양이 많고 설정이 어렵다.강의에서 여러 설정을 잡고 최종적으로 REST Docs문서를 생성하여 브라우저를 통해 확인해보았다. 테스트 과정을 거치며 각각의 문서 조각들이 모여 하나의 문서가 되는 것이 재밌었다. 4주차 회고Keep (만족했고, 앞으로도 지속하고 싶은 부분)테스트 코드를 짤 때 어떤 점이 문서화를 할 때 좋을지 다시 한번 생각해볼 수 있으며, 각종 어노테이션을 습득할 수 있었다. 더불어 api를 많이 짤 일이 생길 텐데 이렇게 REST Docs를 통해 문서 규격을 자동화하여 관리할 수 있다는 점이 너무 유용하고 값진 경험이였다. 앞으로 토이프로젝트를 하면서도 많이 사용해볼 예정이다..Problem (아쉬웠던 점)전반적으로 이번 강의를 마치면서 강사님의 생각을 내가 완전히 따라가지는 못했다는 생각이 많이 든다. 정말 훌륭한 강의를 펼쳐주시지만 내가 모든 것을 내꺼로 체화시키는 과정은 별도로 필요해보인다. 남이 하는걸 봤을때 쉬워보이면 그 사람이 정말 잘하는 거라고 하던데 나도 그런 경지가 되고 싶다는 생각이 들었다. Try (다음에 시도해볼 점)전반적으로 배운 내용을 적용해본 토이프로젝트를 진행할 예정이다. 클린코드와 테스트코드 원칙을 기반으로 서비스를 런칭시켜볼 예정이다. 너무 많은 것을 배워 행복한 일주일이였다.