로깅, 테스트, Devtools (스프링 부트 활용 - 4)
1. 로깅
- 로깅 퍼사드 vs 로거
Commons Logging, SLF4j / JUL, Log4J2, Logback
로깅 퍼사드는 실제 로깅을 하는 것이 아니라 로거 기능을 추상화한 인터페이스임
로깅 퍼사드의 장점 : 로깅 퍼사드 밑의 로거를 바꾸어 낄 수 있음
-> 주로 프레임워크는 퍼사드를 이용해 개발함
만약 어떤 프레임워크에서 특정 로거를 쓴다면, 해당 프레임워크를 사용하는 모든 어플리케이션은 해당 로거를 사용해야 함
기존에는 콘솔 출력만 하는데, 다음 설정으로 로그 파일 저장 가능
// 둘 중 하나만 설정
logging.path=logs // 디렉토리 설정
logging.file=logfile // 파일 설정
로그 파일은 10MB 마다 롤링이 되고 나머지는 아카이브가 됨.
- 로그로 남기기
private Logger logger = LoggerFactory.getLogger(SampleRunner.class);
logger.debug("Message");
2. 테스트
spring-boot-starter-test 의존성 추가
- @SpringBootTest (통합 테스트)
@RunWith(SpringRunner.class) 랑 같이 사용해야 함
@SpringBootTest 는 @SpringBootApplication으로 찾아가서 component-scan을 해서 빈으로 등록시키고,
@MockBean은 다시 목 빈 객체를 만들어 기존 빈을 대체시킴
-> 아주 큰 통합된 테스트임!
- WebEnvironment.MOCK
내장 톰켓을 구동하지 않고, 구동하는 것처럼 테스트
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void hello() throws Exception {
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("hello hongchan"))
.andDo(print());
}
}
- WebEnvironment.RANDOM_PORT
내장 톰켓 사용하여 테스트
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {
@Autowired
TestRestTemplate testRestTemplate;
@Test
public void hello() {
String object = testRestTemplate.getForObject("/hello", String.class);
assertThat(object).isEqualTo("hello hongchan");
}
}
- @MockBean
ApplicationContext에 들어있는 빈을 Mock으로 만든 객체로 교체한다.
모든 @Test 마다 자동으로 리셋
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {
@Autowired
TestRestTemplate testRestTemplate;
// Controller가 사용하는 service 대신 mock Service로 대체하여 테스트를 사용
// 끊어낼 수 있어서 서비스 단 까지 가지 않아도 됨
@MockBean
SampleService mockSampleService;
@Test
public void hello() {
when(mockSampleService.getName()).thenReturn("jiyun");
String object = testRestTemplate.getForObject("/hello", String.class);
assertThat(object).isEqualTo("hello jiyun");
}
}
- WebTestClient
위와 달리 비동기적으로 실행됨 (성능 향상)
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SampleControllerTest {
// webflux 의존성 추가해야 사용 가능
// TestRestTemplate 과 달리 비동기적으로 작동함
// 완료하면 요청이와서 콜백이 실행됨
// API 도 비교적 사용하기 좋음, 이것 때문에 의존성 추가할 정도 (추천)
@Autowired
WebTestClient webTestClient;
@MockBean
SampleService sampleService;
@Test
public void hello() {
when(sampleService.getName()).thenReturn("jiyun");
webTestClient.get().uri("/hello").exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("hello jiyun");
}
}
- 슬라이스 테스트
레이어 별로 빈들이 등록되기 때문에 각 레이어 별로 테스트를 진행할 수 있음 <-> @SpringBootTest (통합테스트)
@JsonTest
@WebMvcTest (컨트롤러 하나만 테스트할 때, 위의 예제에서 Service는 빈으로 등록 안됨! @MockBean 사용해야 함)
@WebFluxTest
@DataJpaTest
- @OutputCapture
특정 로그 메시지가 출력이 되는지 테스트 코드로 확인하고 싶을 때 유용함
3. Spring-Boot-Devtools
완벽하지는 않아서 잘 쓰지는 않음
- 캐시 설정을 개발 환경에 맞게 변경 (꺼줌)
- 코드를 변경하고 빌드하면 빠르게 재시작해줌
인프런 백기선님 '스프링 부트’ 강의를 듣고 정리한 내용입니다.