데브코스 백엔드 3기 25일차

금월!
log와 단위테스트, 통합테스트에 대해 배웠다


logback 설정하기

log관련 설정은 logging framework 설정에 따르게 됨

  • 실제 로그를 남기는건 logback framework
    = logback 설정을 통해 logging 설정 할 수 있음
    • logback : 다양한 설정파일을 읽을 수 있음 + 읽는 순서가 정해져 있음
      • logback-test.xml 찾음(src-test-resources)
      • 없으면 -> ‘logback.groovy` 찾음(src-main-java-resources)
      • 없으면 -> logback.xml 찾음
      • 없으면 -> 기본설정 전략 따름(BasicConfiguration)


  • 설정파일의 루트요소는 <configuration>
    • 해당 루트요소 안에 <appender>, ‘` 존재
      • <root> :classpath상에서 사용되는 모든 logger에 적용
      • <appender> 통해 로그 출력
        어디에 어떤 포맷으로 로그를 남길 수 있는지 설정하는 것
        이 설정에 따라 콘솔(ConsoleAppender), 파일(FileAppender), DB에도 남길 수 있음
        • <encoder> 안의 pattern
          특정한 loger의 level 지정가능


  • logback이 기본적으로 제공하는 pattern layout
    • RollingFileAppender
    • TimeBaseRollingPolicy : 시간이 지나면 자동으로 로그 기록파일 만들어줌
      => 둘이 같이쓰면 -> 오늘 날짜로그는 무조건 access.log에 하루지나면 access-%d{yyyy-MM-dd}로 이름 바뀜
      (오늘 날짜 몰라도 access.log만 봐도됨)



SpringBoot starter

(SpringBoot는 많은 starter모듈 제공해줌 ex) JDBC starter, spring-boot-starter-mail)

  • 일종의 pom 파일(어떻게 보면 메이븐설정만 들고있는 프로젝트)
  • Spring Application 만드는 데 필요한 dependency들 자동으로 구성되어 있음
    -> 빠르게 start할 수 있게 해준다는 의미


  • 알아서 관련 dependency들이 만들어지게 구성
    • spring-boot라는 dependency 가짐
    • spring-core
    • spring-boot-starter-logging
    • spring-boot-test



소프트웨어 테스팅

단위테스트

자동화 테스트를 위한
application에서 가장 작은 단위를 테스트하는 것 = 고립해서 테스트한다
(하나의 클래스 or 메소드를 하나의 단위로 테스트)


단위테스트 하는 이유

  1. 새로 추가한 기능이 이미 배포한 기존 기능에 영향을 미치지 않게
  2. 테스트케이스만 보고도 이런 기능이 있구나!(이런 상황에 이런 메소드가 오면 이런 결과가!)
    1) given : 특정한 상황을 주어줌 2) when : 특정행위 호출 3) then : 결과확인


SUT(System Under Test)
테스트하는 대상

  • method : SUT에서 제공하는 기능
  • Test Double : 의존관계에 있는 다른객체(=협력관계자)를 실제로 사용하지 않고 Test Double로 대체
    • Mock(mock, spy) : 행위검증(행위에 집중)
      • method의 return값으로 판단할 수 없는 경우, 특정 동작 수행하는지 확인
      • Mock Object 생성 도와주는 test framework : Mockito, JMock, EasyMock
    • Stub(stub, dummy, fake) : 상태검증
      • 메서드 수행 후 객체상태 확인 -> 올바르게 동작했는지 확인



통합테스트

테스트하고자 하는 코드를 다른 의존관계와 연동이 잘 되는지 테스트 or 외부시스템(ex) DB)과 연동테스트


End-to-end test

business flow가 정상적으로 동작함을 테스트

  • UI(button click) -> API 호출 -> Controller-Service-DB -> UI



JUnit

Open source Test Framework

  • 제공하는 기능
    • 매 단위 테스트마다 TestClass instance 생성
      -> 독립적인 테스트 가능 = 이전 클래스가 다음 테스트에 영향 안줌
    • IDE tool에서도 test code 쉽게 실행가능
    • annotation 제공 -> test lifecycle 관리 + 테스트코드 간결
      ex) @BeforeAll, @BeforeEach
    • assert method -> 테스트케이스 결과 판별 쉽게(녹색-성공, 빨강-실패)


JUnit4 vs JUnit5

  • JUnit4 : 하나의 module, monolithic architecture
    • junit.jar
  • JUnit 5 : 3개의 모듈로 분리(jar가 3개)
    • JUnit Platform : JVM상에서 test framework 런치하기 위한 기반 제공
      • test engine interface
      • 테스트를 발견하고 실제로 실행하고 결과를 보고해줌
    • JUnit Jupitor : test engine의 실제 구현체(JUnit5)
    • JUnit Vintage : test engine의 실제 구현체, JUnit4로 작성한 테스트코드 실행 시 사용


JUnit5

  • @BeforeAll : 클래스 생성전에 초기화 될 때 한먼만 실행 -> static void
  • @BeforeEach : 매 메소드마다 실행됨


  • Jupiter method
    • assertEquals
    • assertNotEquals
    • assertThrows
    • assertAll : 여러개 한번에



Hamcrest library

다양한 Matcher 제공

  • spring-boot-starter-test -> hamcrest 자동으로 dependency 추가
  • Matcher는 interface
    • Matchers가 구현체
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;



기존 Jupiter의 Assertions와 비교

  • assertEquals(assertNotEquals) & assertThat
@Test
@DisplayName("여러 hamcrest matcher 테스트")
void hamcrestTest() {
    assertThat(1 + 1, equalTo(2));
    assertThat(1 + 1, is(2));
    assertThat(1 + 1, anyOf(is(1), is(2)));

    assertThat(1 + 1, not(equalTo(1)));
}


  • 컬렉션에 대한 Matcher test
@Test
@DisplayName("여러 hamcrest matcher 테스트")
void hamcrestListTest() {
    List<Integer> prices = List.of(2, 3, 4);
    assertThat(prices, hasSize(3));
    assertThat(prices, hasItem(3));
    assertThat(prices, hasItem(greaterThan(2)));
    assertThat(prices, hasItem(greaterThanOrEqualTo(2)));
    assertThat(prices, containsInAnyOrder(3, 4, 2));
    assertThat(prices, everyItem(greaterThan(1)));
}



Spring Container 없이

단위테스트 어떻게 해야하는지

-> Mock 객체 만들어서
=> Spring Framework에서 우리가 Mock으로 만들기 어려운 부분(ex) Environment, JNDI, Servlet API, Spring Web Reactive)을 지원해줌
  +) util class들 : General Testing Utilities, Spring MVC Testing Utilities
=> 그러나 실제 단위테스트코드 작성 시 이런 의존관계 없이 핵심로직을 잘 작성하는게 중요!
= 비즈니스로직은 Spring에 의존적이지 않게!


통합테스트 어떻게 해야하는지

서버를 띄우지 않고 Spring Container 내에서 각각 등록된 bean들간의 연동되어진 부분을 테스트

  • 테스트 시 Spring Container 필요(테스트 시 IoC Container 제공하기 위해서)
    => Spring은 TestContext Framework 제공해줌(관리해주는애는 TestContextManager)
    • 테스팅환경에서 applicationContext를 annotation만 사용해서 쉽게 만들 수 있음
    • 캐싱기능(같은 내용의 container -> 새로 만들지 않고 재사용)
  • SpringTestContext Framework를 사용하기 위해서
    • @ContextConfiguration : 스프링 내부에서 어떤식으로 ApplicationContet만들어지는지만 알려줌
      • @Autowired ApplicationContext applicationContext;
    • @ExtendWith(SpringExtension.class) : 실제로 JUnit과 상호작용해서 TestContext가 만들어지게 하는건 SpringExtension 이용해야함
    • @SpringJUnitConfig = @ContextConfiguration + @ExtendWith



일기(회고)

  • 코드리뷰 두가지를 다 욕심내려니 힘들다..!
    그래도 하는데까지는 해보고싶다 덕분에 너무 졸리다
    그만큼 많이 배우는 느낌~~
    강의 양도 점점 많아진다 힘을 내보자


  • 오늘의 게더
    • 금요일 게더긴 하지만ㅎ 토욜 내 생일 전!

    1103-1


업데이트: