테스트 코드를 이용한 테스트
- 서버를 띄우고 http 요청과 응답을 확인할 수 있다.
- 그런데 매번 직접 확인하는 것은 번거로운 일이다. ex) 헤더, 바디 등
- 테스트 코드를 사용하면 효율적이다.
- Spring initializer를 통해 애플리케이션을 처음 세팅하면 "test" 폴더 안에 TestClass 가 생성된다.
- 애플리케이션이 기본적으로 스프링 부트를 기반으로 작동한다.
- API 요청 라이브러리 RestTemplate vs TestTemplate
- RestTemplate: 정상이 아닌 경우, 예외를 던진다.
- TestRestTemplate: 응답 자체를 그대로 가져오기 때문에 에러가 난 경우 사용할 때 적합하다. status code, content-type 이 뭔지 파악할 수 있어 편리하다.
- Assertions.assertThat()을 이용해서 검증하면 편리하다.
- Response
- getHeaders()를 이용하면 헤더를 담은 컬렉션을 리턴한다.
Ex)
<hide/>
@Test
void helloApi() {
TestRestTemplate rest = new TestRestTemplate();
ResponseEntity<String> response = rest.getForEntity(
"http://localhost:8080/hello?name={name}", String.class, "Spring");
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE)).startsWith(
MediaType.TEXT_PLAIN_VALUE);
assertThat(response.getBody()).isEqualTo("Hello! Spring");
}
DI와 단위 테스트
- Service 클래스 안에 어떤 메서드가 있다면 이 로직을 검증하는 방법은 어렵지 않다.
- 직접 API 테스트를 하지 않기 때문에 속도가 빠르고 원하는 대상만 골라서 자바 코드를 직접 테스트하면 된다.
- 서버를 띄우지 않고도 고립된 테스트가 가능하다는 게 장점이다.
- 고립된 테스트: HelloController, HelloService가 있는 경우에 대해 HelloController의 결함에 상관 없이 HelloService를 테스트하거나 HelloService 결함에 상관없이 HelloController를 테스트하는 걸 말한다.
<hide/>
@Test
void sayHello() {
SimpleHelloService helloService = new SimpleHelloService();
String ret = helloService.sayHello("Test");
assertThat(ret).isEqualTo("Hello! Test");
}
Ex) 고립된 테스트
- 컨트롤러 테스트
- 아래와 같이 만들면 컨트롤러에만 국한시켜서 테스트할 수 있다. 서비스 클래스 코드의 결함에는 관련이 없는 테스트이다.
<hide/>
@Test
void hello() {
HelloController helloController = new HelloController(name -> name);
String ret = helloController.hello("test");
assertThat(ret).isEqualTo("test");
}
- 컨트롤러
- null인 경우 예외처리된다.
<hide/>
@GetMapping("/hello")
public String hello(String name) {
return helloService.sayHello(Objects.requireNonNull(name));
}
- assertThatThrownBy()를 이용하면 실패 케이스에 대해서 적절한 예외가 터지는지 확인할 수 있다.
- 컨트롤러 메서드의 반환형을 보면 위와 같이 null이면 에러 처리되고 있다.
<hide/>
@Test
void failsHelloController() {
HelloController helloController = new HelloController(name -> name);
assertThatThrownBy(
() -> {
String ret = helloController.hello(null);
}).isInstanceOf(NullPointerException.class);
}
- api test - 500 error
<hide/>
@Test
void failHelloApi() {
TestRestTemplate rest = new TestRestTemplate();
ResponseEntity<String> response = rest.getForEntity(
"http://localhost:8080/hello?name=", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
}
DI를 이용한 Decorator, Proxy 패턴
- 데코레이터 패턴을 적용해서 핼로 데코레이터 클래스를 만들 계획이다.
- 컨트롤러 - 서비스 사이에 핼로 데코레이터 클래스를 위치시킨다.
- 현재 컨트롤러가 서비스 클래스에 의존하고 있다.
- 데코레이터 클래스를 만들면 다음과 같은 에러가 난다.
- 이 상태로 서버를 띄우면
- Parameter 0 of constructor in tobyspring.helloboot.HelloController required a single bean, but 2 were found:
- 와 같은 에러가 난다.
- HelloController 빈이 하나만 필요한데 두 개나 만들어졌기 때문이다.
- 만약 이 두 개의 빈을 생성해두고서 우선 순위로 쓰려는 빈을 등록하고 싶은 경우는 @Primary 를 사용하면 된다.
- 데코레이터 위에 @Primary를 붙이면 대코레이터 클래스를 우선적으로 갖다 쓴다.
- 테스트
<hide/>
@Test
void helloDecorator() {
HelloDecorator decorator = new HelloDecorator(name -> name);
String ret = decorator.sayHello("Test");
Assertions.assertThat(ret).isEqualTo("*Test*");
}
- 프록시패턴: 실제 빈을 최대한 지연시켜서 가져와야할 때 사용할 수 있다.
출처 - 인프런 토비의 스프링
'Spring Framework > 토비의 스프링' 카테고리의 다른 글
Chapter 07. 조건부 자동 구성 (0) | 2023.07.24 |
---|---|
Chapter 06. 메타 애너테이션과 합성 애너테이션 (2) | 2023.07.14 |
Chapter 04. 독립 실행형 스프링 애플리케이션 (0) | 2023.06.24 |
Chapter 03. 독립 실행형 서블릿 애플리케이션 (0) | 2023.06.20 |
Chapter 02. 스프링 부트 시작하기 (0) | 2023.06.18 |