프로그래밍/Java

spring boot gradle REST API 서버 테스트 구축

소행성왕자 2025. 1. 17. 16:26

java 17 과 spring boot 3.1 사용

build.gradle

plugins {
	id 'java'
	id 'war'
	id 'org.springframework.boot' version '3.1.0'
	id 'io.spring.dependency-management' version '1.1.6'
	id 'application'  // 추가
	id "com.github.node-gradle.node" version "7.1.0"
}

group = 'com.coforward'
version = '0.0.1-SNAPSHOT'

java {
	toolchain {
		languageVersion = JavaLanguageVersion.of(17)
	}
}

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-devtools'
	implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.0'
	implementation 'com.fasterxml.jackson.core:jackson-databind'
	implementation 'org.springframework.boot:spring-boot-starter-websocket'
	implementation 'jakarta.websocket:jakarta.websocket-api'
	implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
	implementation 'com.google.code.gson:gson:2.10.1' 
	implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
	compileOnly 'org.projectlombok:lombok'
	annotationProcessor 'org.projectlombok:lombok'
	providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
	implementation 'org.springframework.boot:spring-boot-starter-tomcat'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
	runtimeOnly 'mysql:mysql-connector-java:8.0.25'
	implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'

}

tasks.named('test') {
	useJUnitPlatform()
}

 

프로젝트 구조

ResourceController.java

package com.coforward.egfwts.vdtResource.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import com.coforward.egfwts.vdtResource.dto.MyResource;
import com.coforward.egfwts.vdtResource.service.ResourceService;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/api/resources")
public class ResourceController {

    @Autowired
    private ResourceService resourceService;

    // GET: 리소스 조회
    @GetMapping
    public ResponseEntity<List<MyResource>> getAllResources() {
        return ResponseEntity.ok(resourceService.getAllResources());
    }

    // GET: 리소스 조회 (ID로)
    @GetMapping("/{id}")
    public ResponseEntity<MyResource> getResourceById(@PathVariable Long id) {
        Optional<MyResource> resource = resourceService.getResourceById(id);
        return resource.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
    }

    // POST: 리소스 생성
    @PostMapping
    public ResponseEntity<MyResource> createResource(@RequestBody MyResource resource) {
        MyResource createdResource = resourceService.createResource(resource);
        return new ResponseEntity<>(createdResource, HttpStatus.CREATED);
    }

    // PUT: 리소스 수정
    @PutMapping("/{id}")
    public ResponseEntity<MyResource> updateResource(@PathVariable Long id, @RequestBody MyResource updatedResource) {
        MyResource resource = resourceService.updateResource(id, updatedResource);
        return resource != null ? ResponseEntity.ok(resource) : ResponseEntity.notFound().build();
    }

    // PATCH: 리소스 부분 수정
    @PatchMapping("/{id}")
    public ResponseEntity<MyResource> patchResource(@PathVariable Long id, @RequestBody MyResource partialResource) {
        MyResource resource = resourceService.patchResource(id, partialResource);
        return resource != null ? ResponseEntity.ok(resource) : ResponseEntity.notFound().build();
    }

    // DELETE: 리소스 삭제
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteResource(@PathVariable Long id) {
        return resourceService.deleteResource(id) ? ResponseEntity.noContent().build() : ResponseEntity.notFound().build();
    }
}

MyResource.java

package com.coforward.egfwts.vdtResource.dto;

public class MyResource {
    private Long id;
    private String name;

    public MyResource(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    // Getters and Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

ResourceService.java

package com.coforward.egfwts.vdtResource.service;
import org.springframework.stereotype.Service;

import com.coforward.egfwts.vdtResource.dto.MyResource;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class ResourceService {

    private List<MyResource> resources = new ArrayList<>();
    private Long currentId = 1L;

    // 리소스 생성
    public MyResource createResource(MyResource resource) {
        resource.setId(currentId++);
        resources.add(resource);
        return resource;
    }

    // 리소스 조회
    public List<MyResource> getAllResources() {
        return resources;
    }

    public Optional<MyResource> getResourceById(Long id) {
        return resources.stream().filter(resource -> resource.getId().equals(id)).findFirst();
    }

    // 리소스 수정
    public MyResource updateResource(Long id, MyResource updatedResource) {
        Optional<MyResource> existingResource = getResourceById(id);
        if (existingResource.isPresent()) {
            MyResource resource = existingResource.get();
            resource.setName(updatedResource.getName());
            return resource;
        }
        return null;
    }

    // 리소스 부분 수정
    public MyResource patchResource(Long id, MyResource partialResource) {
        Optional<MyResource> existingResource = getResourceById(id);
        if (existingResource.isPresent()) {
            MyResource resource = existingResource.get();
            if (partialResource.getName() != null) {
                resource.setName(partialResource.getName());
            }
            return resource;
        }
        return null;
    }

    // 리소스 삭제
    public boolean deleteResource(Long id) {
        return resources.removeIf(resource -> resource.getId().equals(id));
    }
}

동작 예시

  • GET /api/resources -> 모든 리소스를 조회합니다.
  • POST /api/resources -> 새로운 리소스를 생성합니다.
  • GET /api/resources/{id} -> 특정 ID의 리소스를 조회합니다.
  • PUT /api/resources/{id} -> 특정 ID의 리소스를 전체 수정합니다.
  • PATCH /api/resources/{id} -> 특정 ID의 리소스를 부분 수정합니다.
  • DELETE /api/resources/{id} -> 특정 ID의 리소스를 삭제합니다.

POST 요청 (리소스 생성)

  • URL: http://localhost:8080/api/resources
  • 메서드: POST
  • Body (JSON):
  •  
    {
      "name": "Resource 1"
    }
  • 응답:
  • {
      "id": 1,
      "name": "Resource 1"
    }

 

GET 요청 (모든 리소스 조회)

  • URL: http://localhost:8080/api/resources
  • 메서드: GET

 

GET 요청 (ID로 리소스 조회)

  • URL: http://localhost:8080/api/resources/1
  • 메서드: GET

 

PUT 요청 (리소스 전체 수정)

  • URL: http://localhost:8080/api/resources/1
  • 메서드: PUT
  • Body (JSON):
  • {
      "name": "Updated Resource 1"
    }

 

PATCH 요청 (리소스 부분 수정)

  • URL: http://localhost:8080/api/resources/1
  • 메서드: PATCH
  • Body (JSON):
  • {
      "name": "Partially Updated Resource 1"
    }

 

DELETE 요청 (리소스 삭제)

  • URL: http://localhost:8080/api/resources/1
  • 메서드: DELETE

 

cURL을 사용한 테스트

cURL 명령어를 통해도 테스트할 수 있습니다.

  1. POST 요청 (리소스 생성)
  2. bash
    curl -X POST http://localhost:8080/api/resources -H "Content-Type: application/json" -d '{"name": "Resource 1"}'
  3. GET 요청 (모든 리소스 조회)
  4. bash
    curl -X GET http://localhost:8080/api/resources
  5. GET 요청 (ID로 리소스 조회)
  6. bash
    curl -X GET http://localhost:8080/api/resources/1
  7. PUT 요청 (리소스 전체 수정)
  8. bash
    curl -X PUT http://localhost:8080/api/resources/1 -H "Content-Type: application/json" -d '{"name": "Updated Resource 1"}'
  9. PATCH 요청 (리소스 부분 수정)
  10. bash
    코드 복사
    curl -X PATCH http://localhost:8080/api/resources/1 -H "Content-Type: application/json" -d '{"name": "Partially Updated Resource 1"}'
  11. DELETE 요청 (리소스 삭제)
  12. bash
    curl -X DELETE http://localhost:8080/api/resources/1