
이 글은 인프런 이중석님의 👉[스프링부트-실전-상품주문-tdd] 강의를 들으며 작성하였습니다. (소중한 지식 나눔에 감사드립니다👍)
개인 공부 목적이며 상업적 용도가 아님을 밝힙니다.
강의를 들으며 추가로 궁금한 내용 및 오류를 정리한 글 입니다.
기존 POJO 방식으로 했을때는 테스트에서 모든 필요한 클래스를 선언하고 초기화하여야 했다. (즉, 개발자가 주도적으로 필요한 정보를 관리해야했다)

하지만 SpringBoot는 Spring이 어플리케이션 컨택스트를 설정하고 @Service , @Repository , @Component 등이 붙은 클래스를 빈으로 스프링 컨테이너에 등록한다.
그리고 @Autowired 로 Service를 가져오면 이 Service가 의존하는 빈도 자동으로 주입하게 된다 ( 개발자가 아닌 스프링이 제어를 한다)

Spring 의 IoC(제어의역전) 기술을 이용함으로써 개발자가 필요한 기술을
그때그때 주입하는게 아니라 자동으로 주입할 수 있도록 스프링 컨테이너가 관리하므로 개발의 편의성이 증가한다.
기존 상품등록 테스트를 실제 사용자가 http요청으로 상품정보를 보낸 것처럼 API를 추가하고 201(created)를 응답하는 과정을 추가한 내용입니다.
API 작동을 테스트할 수 있도록 의존성을 추가했다.
이 의존성은 RESTful 웹 서비스를 테스트하는 데 사용되는 자바용 라이브러리이다.
근데 내 경우에 4.4.0은 의존성 오류가 발생했기에 5.4.0으로 대체하니
정상 빌드가 되었다.
testImplementation 'io.rest-assured:rest-assured:4.4.0' //오류

testImplementation 'io.rest-assured:rest-assured:5.4.0' //정상빌드
final ExtractableResponse<Response> response =
RestAssured.given().log().all()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.port(getPort())
.body(request)
.when().post("/products")
.then().log().all().extract();
given() : 요청 정보를 작성해달라
(예: contentType은 Json , log 찍을게 , 데이터는 body에 넣어보낼게)
port() : 요청할 포트 지정
when() : HTTP method 와 path(URL)을 작성해달라
then() : 응답을 어떻게 처리할지 정해달라
(예 : 응답결과를 로그로 보여주고
log().all() : 모든 요청/응답 세부 정보를 로그로 남겨달라
extract() : ExtractableResponse 객체로 추출해달라
ExtractableResponse ( import io.restassured.response.ExtractableResponse; )
응답결과를 객체 형태로 추출해준다.
요약을 하자면, JSON형태로 request를 요청값으로 POST방식으로 /products path로 요청할테니 , 그에 대한 응답을 추출가능한응답객체로 담아서 검증하겠다는 의미이다.
Request method: POST
Request URI: http://localhost:9012/products
...
Headers: Accept=*/*
Content-Type=application/json
...
Body:
{
"name": "상품명",
"price": 1000,
"discountPolicy": "NONE"
}
java.net.ConnectException: Connection refused: connect
문제를 확인해보니 현재 ProductApiTest.java 에도 @SpringBootTest 어노테이션이 붙어있고, 이 클래스가 상속하고 있는 ApiTest 도 @SpringBootTest가 붙어있어 겹쳐서 발생한 문제인 것 같다.
<ProductApiTest.java 코드> [현재 ApiTest 클래스 상속중]

<ApiTest.java 코드>

Request method: POST
Request URI: http://localhost:61548/products
...
Headers: Accept=*/*
Content-Type=application/json
Body:
{
"name": "상품명",
"price": 1000,
"discountPolicy": "NONE"
}
...
HTTP/1.1 404
{
"error": "Not Found",
"path": "/products"
}
당연히 /products 에 대한 컨트롤이 없기때문에 정상적인 리턴값이다.
@RestController
@RequestMapping("/products")
@Component
class ProductService {
private final ProductPort productPort;
ProductService(ProductPort productPort) {
this.productPort = productPort;
}
@PostMapping
public ResponseEntity<Void> addProduct(@RequestBody final AddProductRequest request) {
final Product product = new Product(request.name(), request.price(), request.discountPolicy());
productPort.save(product);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
기존 ProductService.java에 @RestController를 이용,
/products 에 대한 요청을 받고 리턴하도록 세팅을 했다.
Request method: POST
Request URI: http://localhost:61757/products
...
Headers: Accept=*/*
Content-Type=application/json
Body:
{
"name": "상품명",
"price": 1000,
"discountPolicy": "NONE"
}
...
HTTP/1.1 201 //정상 응답 완료!
Content-Length: 0
정상 처리 완료!
혹시 프로젝트를 실행했을 때
Process 'command 'C:\Program Files\Java\jdk-17\bin\java.exe'' finished with non-zero exit value 1

같은 에러가 난다면 file > settings > build,execution,deplayment > gradle > Build를 Gradle 이 아니라 intelliJ 로 설정한다.

