TestCode

Shaun·2024년 1월 11일
1
post-thumbnail

코드를 짤때 항상 로직부터 구현하고 테스트 코드를 짜온것 같다. 그 방법에 대한 문제점과 해결방안을 알아보자

해피 케이스와 예외 케이스 구별하자

  • 해피케이와 예외케이스 검증시 경계값(이상,이하 초과,미만) 테스트를 하자

테스트하기 어려운 영역을 구분

테스트하기 어려운영역

  • 관측할 때마다 다른 값에 의존하는 코드(현재날짜/시간/랜덤 값/전역변수)는 외부에서 받도록 하자

  • 외부 세계에 영향을 주는 코드(데이터베이스기록,메시지발송..)

테스트하기 쉬운 영역

  • 같은 입력에는 항상 같은 결과

  • 외부 세상과 단절된 형태

  • 테스트 하기 쉬운 코드

테스트는 문서다

  • 프로덕션 기능을 설명하는 테스트 코드 문서

  • 다양한 테스트 케이스를 통해 프로덕션 코드를 이해하는 시각과 관점을 보완

DisplayName은 섬세하게

  • 테스트 행위에 대한 결과까지 기술한다.

  • 명사의 나열보다는 문장으로 표기하자

  • 도메인 용어를 사용하여 한층 추상화된 내용 담기

  • 테스트 현상을 중점으로 기술하지 말것

TDD

  • 프로덕션 코드보다 테스트 코드를 먼저 작성하여 테스트가 구현과정을 주도하도록 하는 방법론

  • 최대한 빠르게 초록불을 보도록한다 그리고 나서 리팩토링

선 기능 구현, 후 테스트 작성

  • 테스트 자체의 누락 가능성

  • 특정 테스트 케이스만(해피케이스)만 검증할 가능성

  • 잘못된 구현을 다소 늦게 발견할 가능성

선 테스트 작성, 후 기능 구현

  • 복잡도가 낮은, 테스트 가능한 코드로 구현할 수 있게 한다.

  • 쉽게 발견하지 어려운 엣지 케이스를 놓치지 않게 해준다.

  • 구현에 대한 빠른 피드백을 받을 수 있다.

  • 과감한 리팩토링 가능

BDD

  • TDD에서 파생된 기법

  • 함수에 초점을 맞춘 테스트보다는 시나리리오에 기반한 테스트케이스(TC)자체에 집중하여 테스트

  • given/when/then

Layered Atchitecture

Persistence Layer

  • data access 역활

  • 비즈니스 가공로직 포함되면 안된다. data에 대한 crud에만 집중한 레이어

Business Layer

  • persistence Layer와의 상호작용을 통해 비즈니스 로직을 전개 시킨다

  • 트랜잭션을 보장해야 한다.

Presentation Layer

  • 외부 셰계의 요청을 가장 먼저 받는 계층

  • 파라미터에 대한 최소한의 검증을 수행한다.

  • 하위에 있는 두 레이어는 mocking 처리 , WebMvcTest를 사용해 컨트룰러 관련 빈들만 올려주자

@Transactional

  • @DataJpaTest : Jpa관련된 빈들만, 롤백 있음

  • @SpringBootTest : 롤백 없음, 클렌져 만들어 주던가 아니면 트랜잭션 애노테이션 붙어야함

  • @Transactional 이 붙은 testCode가 통과하면 프로덕션 코드에도 있다고 착각할 수 있으니 주의하자!!

  • @Transactional에서 read= only 여부에 따라 MasterDB에 보낼지 slaveDB에 보낼지 DB 엔드포인트 구분 가능

Mock

  • 가짜 객체

  • 먹처리 -> 테스트할때 의존관계에 있는것들을 가짜로 처리한다. 그래서 테스트 하려하는 레이어에 좀 더 집중할 수 있음

@MockBean / MockMvc /@ebMvcTest

WebMvcTest

  • Presentation Layer 관련 빈들만 등록

MockMvc

  • Mock객체를 사용해 스프링 MVC동작을 재현할 수 있는 테스트 프레임워크

@MockBean

  • 컨테이너에 mock으로 만든 객체를 넣어준다.(Spring context)

  • Presentation Layer 테스트시 (@WebMvcTest) service 빈들은 등록 안됨 그래서 가짜로 마들어줄 필요가 있다.(@MockBean)

  • 우리가 어떤 요청을 했을때 어떻게 리턴하면 좋겠다라고 설정 할수 있다.(=Stubbing)(=Mocking을 사용한 테스트)

테스트 코드 작성 팁

  • 엔티티에 있는 Validation 체크는 service 단에서 체크 x

  • Controller entity -> DTO -> ServiceDTO -> Service 로 Service DTO로 한번더 변환 시켜주자 그렇지 않으면 의존성 @Valid를 계속 Service단에 들고 가야하기 때문

  • service에서 컨트룰러 DTO에 의존하지 않음으로써 의존성 분립

  • 큰단위로 테스트 만들면서 필요한 작은단위(메서드) 테스트 코드를 작성해 준다.

Test Double

  • Dummy : 아무것도 하지 않는 깡통 객체
  • Fake : 단순한 형태로 동일한 기능은 수행하나, 프로덕션에서 쓰기에는 부족한 객체
  • Stub : 테스트에서 요청한 것에 대해 미리 준비한 결과를 제공하는 객체(상태검증)
  • Spy : Stub이면서 호출된 내용을 기록하여 보여줄 수 있는 객체
  • Mock : 행위에 대한 기대를 명세하고, 그에 따라 동작하도록 만들어진 객체(행위검증)

순수Mock/@Mock / @Spy/ InjectMocks

순수Mock

  • 순수 mock로 mocking 처리 후 Stubbing 처리

@Mock

  • @Mock 사용시 클래스 상단에 @ExtendWith 선언 해줘야함

@Spy

  • 실제 객체를 기반으로 만들어짐 (Stubbing 사용시 do 사용)

  • 일부는 Mocking처리 Stubbing을 사용하고 일부는 실제 객체 로직 사용하고 싶을때

BDDMockito

  • given 절인데 when 문법을 사용하고 있음. 이를 고치려고 나온게 BDDMockito

  • mockito를 bdd로 한번 감싼것, 기능은 동일

Classicist VS Mockist

  • Mockist : mock으로 테스트를 다하자
  • Classicsit : 실제 객체를 사용해서 테스트 하자

  • 외부 시스템 장애같은경우는 우리가 테스트 하거나 어절수 없다. 그러니 외부 시스템은 잘 동작한다는가정(Mocking) 하에 우리 시스템 테스트

테스트 코드 규칙

한문단 한주제

  • if문과 for문 두개로 친다. 읽는 사람이 생각해야하므로 최대한 지양/ 최대한 논리구조 사용 x
  • 테스트 코드는 볼때 정말 쉽게 읽어지도록 만들기 -> 쉽게 여러개 만들기, 한번에 테스트하려 x

완벽하게 제어하기

  • 제어할수 없는 값은 상위레벨로 올리기, 현재 시간은 쓰지말자

테스트 환경 독립성 보장

  • 2가지 이상 행위가 들어가지 않아야함
  • 테스트 환경은 최대한 생성자 기반으로!(팩토리메서드 말고 순수생성자로) -> 팩토리메서드도 '목적'이 들어간 구문이기 때문
  • 테스트 코드 실패이유가 주행위가 아닌 서브 행위인경우
  • 맥락을 이해하려는데 허들이 있으면 안됌! 최대한 직관적으로!!

테스트간 독립성 보장

  • 공유자원 금지

TestFixture 구성하기

  • given절이 공통된다고 @BeforeEach에 넣지말자, 이 영역에는 아예 몰라도 테스트 내용을 이해하는데 문제가 없는것, Or 수정해도 모든 테스트에 영향을 않는것만 넣어주자
  • 빌더로 given절 생성시 필요한 파라미터만 보내주자 그래야 테스트시 뭐를 볼지 한눈에 들어옴

TexstFixturer 클렌징

  • deleteAll -> 연관된 테이블을 selecet하고 for문으로 건건히 지움
  • deleteAllInBatch -> select과정이 없고 통째로 delete시켜버림.

private 메서드

  • public 메서드 테스트를 할때 private 메서드 또한 포함되어 있으니 자동으로 검증되서 따로 할필요 없다.
  • 반드시 private 메서드를 테스트 해야할 경우 메서드를 따로 분리해 객체를 따로만들어 public으로 만든후 테스트 진행
  • private 메서드 테스트가 필요한경우 이 메서드가 너무 많은 기능을 수행 하지는 않는가, 객체를 분리해야 하는가 고민 필요

@ParameterizedTest

  • 하나의 테스트에 여러개 값을 넣어 테스트 해보고 싶을때 사용(if문이나,for문 지양할때 사용)

테스트 공통환경

  • 공통된 테스트 환경이 있으면 부모클래스로 생성가능
profile
호주쉐프에서 개발자까지..

0개의 댓글