본문 바로가기
아카이브/스프링

스파르타 코딩클럽 [ Spring 심화반 ] - 3주차

by nineteen 2022. 2. 13.
반응형

배운 것

테스트의 필요성

스프링 테스트 프레임워크 (JUnit)

통합테스트

 

 

 

내용 정리

 

테스트의 필요성

 

테스트를 하는 이유는 '버그'를 예방하기 위해서이다.

 

※ 버그

  - 소프트웨어가 예상하지 못한 결과를 내는 것

  - '소스 코드'나 '설계과정에서의 오류'때문에 발생

 

 

현업에서 '버그'란?

  1.   사용자들에게 불편을 준다
    • 일부 기능이 동작하지 않음( 결제, 로그인 등등 )
    • 일부 기능이 의도와 다르게 동작 ( 10만원 결제 -> 100만원 결제 )
    • 전체 기능 동작하지 않음 ( 서비스 접속 불가 )
  2.   회사에 악영향을 끼친다
    • 매출 감소
    • 신뢰도 감소
  3.   '저녁 없는 삶, 주말 없는 삶, 휴가 없는 삶..'의 원인이 된다
    • 버그는 시간을 가려서 발생하지 않음 ( 근무 시간에만 발생 x )
    • 소프트웨어는 스스로 오류를 해결하지 않음

 

어떻게 테스트로 '버그'를 예방할까?

 

  1. 블랙박스 테스트
    • 소프트웨어 내부 구조나 동작원리를 모르는 블랙박스와 같은 상태에서, 즉 웹 서비스의 사용자 입장에서 동작을 검사하는 방법
  2. 개발자 테스트 ( 단위 테스트 )
    • 개발자가 직접 "본인이 작성한 코드"를 검증하기 위해 "테스트 코드"를 작성

 

※ 단위 테스트 ( Unit Test )

  • 프로그램을 작은 단위로 쪼개서 각 단위가 정확하게 동작하는지 검사하고 이를 통해 문제 발생 시 정확하게 어느 부분이 잘못되었는지를 재빨리 확인할 수 있게 해준다

 

 

스프링에서는 '테스트 코드'작성을 잘 할 수 있는 환경을 제공해줌

 

 

스프링 테스트 프레임워크 (JUnit)

 

JUnit이란 자바 프로그래밍 언어용 단위 테스트 프레임워크

 

 

사용 예시

class ProductTest {
    @Test
    @DisplayName("정상 케이스")
    void createProduct_Normal() {
        // given
        Long userId = 100L;
        String title = "오리온 꼬북칩 초코츄러스맛 160g";
        String image = "https://shopping-phinf.pstatic.net/main_2416122/24161228524.20200915151118.jpg";
        String link = "https://search.shopping.naver.com/gate.nhn?id=24161228524";
        int lprice = 2350;

        ProductRequestDto requestDto = new ProductRequestDto(
                title,
                image,
                link,
                lprice
        );

        // when
        Product product = new Product(requestDto, userId);

        // then
        assertNull(product.getId());
        assertEquals(userId, product.getUserId());
        assertEquals(title, product.getTitle());
        assertEquals(image, product.getImage());
        assertEquals(link, product.getLink());
        assertEquals(lprice, product.getLprice());
        assertEquals(0, product.getMyprice());
    }

 

테스트 코드를 작성할 때는 given, when, then으로 구성하는 것이 좋다

  • given : 샘플값
  • when : 테스트할 부분
  • then : 확인, 검증

 

 

ㅇ Mock Object (가짜 객체)

 

각 테스트 케이스는 서로 분리되어야 한다. 이를 위해 가짜 객체(Mock object)를 생성하는 것도 좋은 방법이다

 

  • Controller 클래스만 테스트할 수 없을까?
    • 테스트 범위: Controller, Service, Repository
  • Service 클래스만 테스트할 수 없을까?
    • 테스트 범위: Service, Repository
  • Repository 클래스만 테스트할 수 없을까?
    • 테스트 범위: Repository

 

이러한 문제를 해결하기 위해 가짜 객체를 통해 분리한다.

 

ex)

  • MockRepository
    • 실제 객체와 겉만 같은 객체!
      • 동일한 클래스명, 함수명
    • 실제 DB 작업은 하지 않음
      • DB 작업이 이뤄지는 것처럼~
      • 테스트를 위해 필요한 결과값을 return

 

 

ㅇ Mockito 프레임워크 사용하기

 

Mock 객체를 쉽게 만들 수 있는 방법을 제공한다

@ExtendWith(MockitoExtension.class) // Mockito 프레임워크 사용
class ProductServiceTest {
    @Mock // 가짜 객체를 생성
    ProductRepository productRepository;
    ...

직접 Mock Object를 구현하는 것보다 훨씬 편리

 

※ 사용 케이스를 제대로 정의해줘야 함

 

 

 

 

통합 테스트

 

  1. 단위 테스트 (Unit Test)
    • 하나의 모듈이나 클래스에 대해 세밀한 부분까지 테스트 가능
    • 모듈 간에 상호 작용 검증 못함
  2. 통합 테스트 (Integration Test)
    • 두 개 이상의 모듈이 연결된 상태를 테스트
    • 모듈 간의 연결에서 발생하는 에러 검증 가능
  3. E2E 테스트 (End to End Test)
    • 실제 사용자의 실행 환경과 거의 동일한 환경에서 테스트 진행 (=블랙박스 테스팅)

 

ㅇ 스프링 부트를 이용한 통합 테스트

  • 단위 테스트 시, 스프링은 동작하지 않는다.
    • DI를 할 수 없음
    • DB에 저장 못함
  • @SpringBootTest
    • 테스트 수행 시, 스프링이 동작되도록 하는 어노테이션
      • Spring IoC 사용 가능
      • Repository 사용해 DB CRUD 가능
    • 통합 테스트 가능
    • End to End 테스트 가능
      • Client 요청 → Controller → Service → Repository → Client 응답
  • @Order(1), @Order(2), ...
    • 테스트의 순서를 정할 수 있다

 

 

 

느낀 점 / 보완할 점

어렵다

테스트 코드 작성하는 방법에 대해서 더 공부해봐야 할 듯

 

배운 걸 적용해보는 시도가 중요한 거 같음

이론도 중요하지만 직접 적용해봐야 기억에 더 남는 거 같다