프로그래밍/스프링

단위 테스트

스루나루 2024. 6. 25. 00:28
728x90
728x90

 

 

서론

 

테스트는 간편하게 해야하고 기계가 알아서 통과 여부를 확인할 수 있게 짜야한다.

수동 테스트처럼 일일이 화면 클릭해서 확인하고 감에 의존해서 합격 불합격하는 테스트는 신뢰성이 낮다 

 

 

이게 괜찮은 테스트 코드인가?

    @Test
    void add() {
        CafeKiosk cafeKiosk = new CafeKiosk();
        cafeKiosk.add(new Americano());

        System.out.println(" == 담긴 음료수 수 : " + cafeKiosk.getBeverages().size());
        System.out.println(" == 담긴 음료수  : " + cafeKiosk.getBeverages().get(0).getName());

    }

 

- 사람이 테스트 실행시킨 다음 사람이 콘솔보고 확인함 

- 다른 사람은 뭐가 성공 케이스이고 뭐가 실패인지 알 수가 없음!!

 

 

본문 

 

괜찮은 테스트 코드는 사람 손 안타고 코드로 자동화 시켜서 컴퓨터가 합격 불합격 검증해주는 것을 말한다. 


단위테스트 

 - 작은 코드 단위( 클래스 , 메서드 )를 독립적으로 검증하는 테스트

 - 검증 속도가 빠르고 안정적임 

 

Junit5

- 단위 테스트를 위한 테스트 프레임워크 

 

    @Test
    void add(){
        CafeKiosk cafeKiosk = new CafeKiosk();
        cafeKiosk.add(new Americano());

        assertThat(cafeKiosk.getBeverages().get(0).getName()).isEqualTo("Americano");
        assertThat(cafeKiosk.getBeverages()).hasSize(1);
    }

 

 

 

테스트 케이스 세분화 

- 암묵적이거나 아직 드러나지 않는 요구사항이 있는지 반드시 질문하기 

- 경계값 테스트 : 범위 ( 이상 , 이하, 초과, 미만 ), 구간 ,날짜 등의 테스트를 해야함!!

   ex) 3이상인 경우 해피케이스로 3넣고 예외케이스로는 2넣기 

 

ex) 요구사항 : 같은 음료를 여러잔 담는 기능 추가 

1) 해피 케이스

 - 같은 음료 2잔 넣어서 정상인가 확인 

2) 예외 케이스

 - 경계값이 0이니까 0을 넣어서 예외터지는 거 확인 

 

ex2) 요구사항 : 가게 운영시간 (10:00 - 22:00) 외에는 주문을 생성할 수 없다 

 

    public Order createOrder(){

        LocalDateTime currentDateTime = LocalDateTime.now();
        LocalTime currentTime = currentDateTime.toLocalTime();
        if(currentTime.isBefore(SHOP_OPEN_TIME) || currentTime.isAfter(SHOP_CLOSE_TIME)){
            throw new IllegalArgumentException("주문 시간이 아닙니다. 관리자에게 문의하세요.");
        }

        return new Order(LocalDateTime.now(),beverages);
    }
    
        @Test
    void createOrder(){
        CafeKiosk cafeKiosk = new CafeKiosk();
        Americano americano = new Americano();
        cafeKiosk.add(americano);

        Order order = cafeKiosk.createOrder();

        assertThat(order.getBeverages()).hasSize(1);
        assertThat(order.getBeverages().get(0).getName()).isEqualTo("Americano");
    }

 

- 해당 테스트는 특정 시간에만 통과되니까 좋지 못함 

 

 테스트 빡센 부분을 분리할 줄 알아야함 

 

// 사용자의 현재 시간이었던 부분을 컨트롤 가능하도록 파라미터로 빼서 테스트 용이하게 바꿈 
public Order createOrder(LocalDateTime currentDateTime){

        LocalTime currentTime = currentDateTime.toLocalTime();
        if(currentTime.isBefore(SHOP_OPEN_TIME) || currentTime.isAfter(SHOP_CLOSE_TIME)){
            throw new IllegalArgumentException("주문 시간이 아닙니다. 관리자에게 문의하세요.");
        }

        return new Order(LocalDateTime.now(),beverages);
    }
    
@Test
void createOrderCurrentTime(){
    CafeKiosk cafeKiosk = new CafeKiosk();
    Americano americano = new Americano();
    cafeKiosk.add(americano);

    // 경계값 10시
    Order order = cafeKiosk.createOrder(LocalDateTime.of(2024,6,25,10,0));

    assertThat(order.getBeverages()).hasSize(1);
    assertThat(order.getBeverages().get(0).getName()).isEqualTo("Americano");
}

@Test
void createOrderOutsideOpenTime(){
    CafeKiosk cafeKiosk = new CafeKiosk();
    Americano americano = new Americano();
    cafeKiosk.add(americano);

    // 경계값 10시 보다 1분 늦은 9시 59분
    assertThatThrownBy(()->cafeKiosk.createOrder(LocalDateTime.of(2024,6,25,9,59)))
            .isInstanceOf(IllegalArgumentException.class)
            .hasMessage("주문 시간이 아닙니다. 관리자에게 문의하세요.");
}

 

 

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

 

테스트하기 어려운 영역 ( 외부세계에서 들어오는 입력값 )

1) 관측할 떄마다 다른 값에 의존하는 코드 

 - 현재 날짜/시간, 랜덤값, 전역변수, 함수, 사용자 입력 등 

 

2) 외부 세계에 영향을 주는 코드 ( 외부세계로 나가는 값이 있는 코드 )

 - 표준 출력( 로그 ) , 메시지 발송 , 데이터베이스 기록 등 

 

 

테스트하기 좋은 영역 

1) 순수 함수 

- 같은 입력에 항상 같은 결과

- 외부 세상과 단절된 형태 

- 테스트 하기 쉬운 코드 

 

 

참고

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

 

728x90
728x90