[ 박우빈 Practical Testing #2 ] Layered Architecture

김수호·2024년 6월 13일
0
post-thumbnail

Layered Architecture

  • Presentation Layer
    • 외부 세계의 요청을 가장 먼저 받는 계층
    • 파라미터에 대한 최소한의 검증을 수행한다.
  • Business Layer
    • 비즈니스 로직을 구현하는 역할
    • Persistence Layer 와의 상호작용(Data를 읽고 쓰는 행위)을 통해 비즈니스 로직을 전개시킨다.
    • 트랜잭션을 보장해야 한다.
  • Persistence Layer
    • Data Access 의 역할
    • 비즈니스 가공 로직이 포함되어서는 안 된다.
    • Data에 대한 CRUD에만 집중한 레이어

이처럼 Layer 별 관심사가 다르기 때문에 그에 맞춘 테스트를 작성하는 게 좋다.

각 레이어 계층 별로 테스트를 어떻게 진행하면 좋은지, 어떤 점을 주의해야 하는지 알아보자.


Persistence Layer

  • 참고)
    • Persistence Layer 계층은 일반적으로 데이터에 대한 CRUD 처리에 집중한다. 따라서 해당 계층에 대한 테스트는 단위 테스트에 성격에 가깝다. 각 CRUD에 대한 시나리오를 정의하고 결과가 유효한지만 검증하면 되는 것이다. 다만, 스프링을 띄워서 검증해야 하므로 @SpringBootTest 또는 @DataJpaTest 사용이 필요하다.
      • @DataJpaTest 는 JPA 관련된 빈들만 주입을 해줘서 서버를 띄워준다. 따라서 @SpringBootTest 에 비해서 속도가 빠르고 가볍다. 그리고 @DataJpaTest 는 내부에 @Transactional 이 적용되어있다. 따라서 테스트 후 트랜잭션이 자동으로 롤백된다. @SpringBootTest 는 내부에 @Transactional 이 적용되어 있지 않다.
      • 참고) 보통 서비스 레이어에서 @SpringBootTest 를 사용한 통합테스트를 진행하기 때문에, 리포지토리 계층에서 @DataJpaTest 를 사용해서 서버를 한번 더 띄우기 보다는, 통합 테스트시 같이 테스트하는 편이 좋다. (테스트도 비용이다.)

 

Business Layer

  • 참고)
    • Business Layer 계층은 Persistence Layer 와의 상호작용(Data를 읽고 쓰는 행위)을 통해 비즈니스 로직을 전개시킨다. 따라서 테스트시 주로 @SpringBootTest 를 사용한 통합 테스트를 진행한다.
      • 두가지 이상의 클래스나 모듈이 결합할 때의 시너지는 어떻게 날지 예측하기 어렵다. 따라서 통합테스트를 통해서, 단위테스트로는 커버하지 못하는 영역들을 보장해주어야 한다.
    • 주의) 테스트에서 @Transactional 을 적용하게 되면, 프로덕션 코드에 @Transactional 을 누락하더라도 테스트에는 지장이 없을 수 있다. 따라서 사용시 이를 인지해야 하며, 주의해야 한다.

 

Presentation Layer

  • 참고)
    • Presentation Layer 에서는 외부세계에서 들어온 값들을 위주로 검증하는데 집중한다.
      • @WebMvcTest 를 사용해서 컨트롤러 관련된 빈들만 올려서 테스트할 수 있다.
      • 컨트롤러에서 의존하는 서비스나 리포지토리 레이어는 Mocking 하고, 단위테스트 성격으로 테스트를 작성한다.
    • Presentation Layer 테스트 시에는 Persistence LayerBusiness Layer 같은 하위 레이어들은 모두 Mocking 처리해서 테스트한다. Mocking 이라는 것은 가짜 객체를 사용하는 것을 의미한다.
      • MockMvc: 컨트롤러를 테스트하기 위해서는 HTTP 요청/응답에 대한 검증이 필요하다. 스프링에서는 이를 위해 MockMvc 를 제공하고 있으며, 이는 Presentation Layer 을 테스트할 때 사용된다.
        • @WebMvcTest 사용 시 MockMvc 를 주입받을 수 있다. MockMvc 는 애플리케이션을 배포하지 않고도, 서버의 MVC 동작을 테스트 할 수 있는 라이브러리이다.
      • Mokito: 단위 테스트를 위한 Java Mocking Framework 이다. ( 스프링부트 스타터 테스트를 사용하는 경우, 자동으로 포함되어 있다. )
        • Mokito 를 사용해서 하위 계층은 mocking 처리하고, 컨트롤러 계층에 대해서 독립적으로 단위 테스트 성격의 테스트를 진행할 수 있다.
        • @MockBean 를 사용해서 Mock 객체를 빈으로 등록해서 사용할 수 있다.

 

✔️ 참고

  • Presentation Layer 테스트 시에는 크게 두가지를 검증한다.
    • 요청 파라미터가 유효한가?
    • 요청이 처리되어 정상적으로 응답되는가?
    • 여기서 ① 요청 파라미터가 유효한가? 를 검증할 때는, 검증의 성격을 분리해서 판단하는 시야를 가지는 것이 좋다.
      • 도메인 요구사항에 해당하는 유효성 검증
      • 기본적으로 그 타입이 필수적으로 가져야하는 유효성 검증
      • 예를 들어, 상품명은 4자~20자 사이로 입력되어야 한다라는 정책이 있다고 가정할 때, 상품명이 NULL 이거나 빈 문자열인지에 대한 체크는 기본적으로 그 타입이 필수적으로 가져야하는 유효성 체크 라고 볼 수 있다. 그리고 그에 반해, 4자~20자 사이로 입력되어야 한다는 것은 도메인 요구사항에 가까운 검증이라고 볼 수 있다.
      • 그리고 이런 경우, 컨트롤러 계층에서 어떻게든 이 모든 검증을 다 처리하는 것 보다는, 컨트롤러 계층에서는 Spring bean validation 을 사용한 최소한의 검증(ex. @NotBlank, ..)만 하고, 이후의 검증은 도메인 계층이나 서비스 계층 등으로 책임을 위임하는 것이 좋다.
  • Stubbing: mock 객체에 행위를 지정해주는 것을 의미한다.
  • Mockito 의 여러 애노테이션: @Mock, @MockBean, @Spy, @SpyBean, @InjectMocks
    • 참고) @Mock 어노테이션을 적용해서 만든 Mock 객체는 가짜 객체이며, 실제 그 안의 메소드를 사용하기 위해서는 Stubbing 을 해주어야 한다.
    • 참고) @Spy: 일부만 Stubbing 하고, 나머지는 실제 객체 그대로 동작하도록 하고자 할 때 사용한다.
    • 참고) InjectMocks: @Mock이나 @Spy로 생성된 mock 객체를 자동으로 주입해주는 어노테이션이다.
  • BDDMockito: BDD 스타일로 Mockito를 사용할 수 있도록 해주는 래핑 객체

강의를 듣고 정리한 글입니다. 코드와 그림 등의 출처는 박우빈 강사님께 있습니다.

profile
현실에서 한 발자국

0개의 댓글