데브코스 백엔드 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)
- logback : 다양한 설정파일을 읽을 수 있음 + 읽는 순서가 정해져 있음
- 설정파일의 루트요소는
<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) 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) : 상태검증
- 메서드 수행 후 객체상태 확인 -> 올바르게 동작했는지 확인
- Mock(mock, spy) : 행위검증(행위에 집중)
통합테스트
테스트하고자 하는 코드를 다른 의존관계와 연동이 잘 되는지 테스트 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 -> 테스트케이스 결과 판별 쉽게(녹색-성공, 빨강-실패)
- 매 단위 테스트마다 TestClass instance 생성
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로 작성한 테스트코드 실행 시 사용
- JUnit Platform : JVM상에서 test framework 런치하기 위한 기반 제공
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
- @ContextConfiguration : 스프링 내부에서 어떤식으로 ApplicationContet만들어지는지만 알려줌
일기(회고)
- 코드리뷰 두가지를 다 욕심내려니 힘들다..!
그래도 하는데까지는 해보고싶다 덕분에 너무 졸리다
그만큼 많이 배우는 느낌~~
강의 양도 점점 많아진다 힘을 내보자
- 오늘의 게더
- 금요일 게더긴 하지만ㅎ 토욜 내 생일 전!