diff --git a/README.md b/README.md index cafde8a2c..e52d19f4f 100644 --- a/README.md +++ b/README.md @@ -1 +1,75 @@ -# spring-gift-product \ No newline at end of file +# spring-gift-product +## 기능 요구 사항 +* 상품을 조회, 추가, 수정, 삭제할 수 있는 간단한 HTTP API를 구현한다. +* HTTP 요청과 응답은 JSON 형식으로 주고받는다. +* 현재는 별도의 데이터베이스가 없으므로 적절한 자바 컬렉션 프레임워크를 사용하여 메모리에 저장한다. + +**Request** +``` +GET /api/products HTTP/1.1 +``` + +**Response** +``` +HTTP/1.1 200 +Content-Type: application/json +[ + { + "id": 8146027, + "name": "아이스 카페 아메리카노 T", + "price": 4500, + "imageUrl": "https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg" + } +] +``` + +**상품 데이터 관리** +```java +public class ProductController { + private final Map products = new HashMap<>(); +} + +public class Product { + private Long id; + private String name; + private int quantity; + private double price; + // ... +} +``` + +### 1. get +* 모든 product 조회 + * /api/products +* id로 product 선택 조회 + * /api/products/:id + * 없으면 error 발생 +### 2. post +* product 추가 + * /api/products +### 3. put +* product 수정 + * /api/products/:id + * 없으면 error 발생 +### 4. delete +* product 삭제 + * /api/products/:id + * 없으면 error 발생 + + # step 2 +### /api/products/admin +상품 관리 +### /api/products/admin/add +상품 추가 +### /api/products/admin/:id +상품 편집 및 삭제 가능 + + +# step 3 +상품 정보에 옵션을 추가한다. 상품과 옵션 모델 간의 관계를 고려하여 설계하고 구현한다. +* 상품에는 항상 하나 이상의 옵션이 있어야 한다. + +## 프로그래밍 요구 사항 +* H2 데이터베이스를 사용하도록 변경한다. +* 사용하는 테이블은 애플리케이션이 실행될 때 구축되어야 한다. + diff --git a/sql/ddl.sql b/sql/ddl.sql new file mode 100644 index 000000000..9974ad00e --- /dev/null +++ b/sql/ddl.sql @@ -0,0 +1,8 @@ +drop table if exists product CASCADE; +create table product +( + id bigint AUTO_INCREMENT PRIMARY KEY, + name varchar(255), + price int, + imageUrl varchar(255) +); \ No newline at end of file diff --git a/src/main/java/gift/Application.java b/src/main/java/gift/Application.java index 61603cca0..390bd12b4 100644 --- a/src/main/java/gift/Application.java +++ b/src/main/java/gift/Application.java @@ -5,6 +5,7 @@ @SpringBootApplication public class Application { + public static void main(String[] args) { SpringApplication.run(Application.class, args); } diff --git a/src/main/java/gift/SpringConfig.java b/src/main/java/gift/SpringConfig.java new file mode 100644 index 000000000..71c4f7058 --- /dev/null +++ b/src/main/java/gift/SpringConfig.java @@ -0,0 +1,44 @@ +package gift; + +import gift.controller.AdminController; +import gift.repository.JdbcProductRepository; +import gift.repository.MemoryProductRepository; +import gift.repository.ProductRepository; +import jakarta.annotation.PostConstruct; +import javax.sql.DataSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; + +@Configuration +public class SpringConfig { + + private final DataSource dataSource; + + @Autowired + public SpringConfig(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Bean + public AdminController adminController() { + return new AdminController(productRepository()); + } + + @Bean + public ProductRepository productRepository() { + // JDBC를 이용한 데이터베이스 접근 방식 선택 + return new JdbcProductRepository(dataSource); + } + + @PostConstruct + private void initializeDB() { + // 데이터베이스 초기화를 위한 SQL 스크립트 실행 + ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); + populator.addScript(new ClassPathResource("sql/ddl.sql")); // 데이터베이스 초기화 스크립트 경로 지정 + DatabasePopulatorUtils.execute(populator, dataSource); // 데이터베이스 초기화 실행 + } +} diff --git a/src/main/java/gift/controller/AdminController.java b/src/main/java/gift/controller/AdminController.java new file mode 100644 index 000000000..83f042816 --- /dev/null +++ b/src/main/java/gift/controller/AdminController.java @@ -0,0 +1,45 @@ +package gift.controller; + +import gift.repository.ProductRepository; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/api/products/admin") +public class AdminController { + + private final ProductRepository repository; + + public AdminController(ProductRepository repository) { + this.repository = repository; + } + + // 모든 제품을 표시하는 관리자 페이지로 매핑 + @GetMapping("") + public String adminPage(Model model) { + model.addAttribute("products", repository.findAll()); + return "admin"; + } + + // 새 제품을 추가하는 페이지로 매핑 + @GetMapping("/add") + public String getAdminAddPage() { + return "adminAdd"; + } + + // 삭제된 제품을 보여주는 페이지로 매핑 + @GetMapping("/deleted") + public String getAdminDeletedPage() { + return "adminDeleted"; + } + + // 특정 ID의 제품 세부 정보를 보여주는 페이지로 매핑 + @GetMapping("/{id}") + public String getAdminProductDetailPage(@PathVariable Long id, Model model) { + model.addAttribute("product", repository.findById(id).orElse(null)); // Null을 처리하기 위해 orElse(null) 사용 + return "adminProductDetail"; + } +} diff --git a/src/main/java/gift/controller/ErrorController.java b/src/main/java/gift/controller/ErrorController.java new file mode 100644 index 000000000..69e0548a3 --- /dev/null +++ b/src/main/java/gift/controller/ErrorController.java @@ -0,0 +1,14 @@ +package gift.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class ErrorController { + + // 오류 페이지로 매핑 + @GetMapping("/error") + public String errorPage() { + return "error"; + } +} diff --git a/src/main/java/gift/controller/ProductController.java b/src/main/java/gift/controller/ProductController.java new file mode 100644 index 000000000..5f7a38a75 --- /dev/null +++ b/src/main/java/gift/controller/ProductController.java @@ -0,0 +1,68 @@ +package gift.controller; + +import gift.model.Product; +import gift.model.ProductForm; +import gift.repository.ProductRepository; +import java.util.List; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/products") +public class ProductController { + + private final ProductRepository repository; + + public ProductController(ProductRepository repository) { + this.repository = repository; + } + + // 모든 제품을 가져오는 엔드포인트 + @GetMapping("") + public List getAllProducts() { + return repository.findAll(); + } + + // 특정 ID의 제품을 가져오는 엔드포인트 + @GetMapping("/{id}") + public ResponseEntity getProduct(@PathVariable Long id) { + Product result = repository.findById(id).orElse(null); // Optional 처리 + if (result != null) { + return ResponseEntity.status(HttpStatus.OK).body(result); + } + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); + } + + // 새로운 제품을 생성하는 엔드포인트 + @PostMapping(path = "", consumes = "application/json") + public ResponseEntity postProduct(@RequestBody ProductForm form) { + Product product = new Product(form); // ProductForm을 Product로 변환 + Product result = repository.save(product); + if (result != null) { + return ResponseEntity.status(HttpStatus.OK).body(result); + } + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null); // 상태 코드를 BAD_REQUEST로 수정 + } + + // 특정 ID의 제품을 수정하는 엔드포인트 + @PutMapping(path = "/{id}", consumes = "application/json") + public ResponseEntity putProduct(@RequestBody ProductForm form, @PathVariable Long id) { + Product product = new Product(form); // ProductForm을 Product로 변환 + Product result = repository.edit(id, product); + if (result != null) { + return ResponseEntity.status(HttpStatus.OK).body(result); + } + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); + } + + // 특정 ID의 제품을 삭제하는 엔드포인트 + @DeleteMapping(path = "/{id}") + public ResponseEntity deleteProduct(@PathVariable Long id) { + boolean result = repository.delete(id); + if (result) { + return ResponseEntity.status(HttpStatus.OK).body("Successfully deleted"); + } + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Product not found"); // 메시지를 명확히 수정 + } +} diff --git a/src/main/java/gift/model/Product.java b/src/main/java/gift/model/Product.java new file mode 100644 index 000000000..48a3872dc --- /dev/null +++ b/src/main/java/gift/model/Product.java @@ -0,0 +1,71 @@ +package gift.model; + +public class Product { + + private Long id; + private String name; + private int price; + private String imageUrl; + + // 기본 생성자 추가 (JPA나 다른 프레임워크에서 필요할 수 있음) + public Product() { + } + + // 생성자 + public Product(String name, int price, String imageUrl) { + this.name = name; + this.price = price; + this.imageUrl = imageUrl; + } + + // ProductForm을 Product로 변환하는 생성자 + public Product(ProductForm form) { + this.name = form.getName(); + this.price = form.getPrice(); + this.imageUrl = form.getImageUrl(); + } + + // getter 메서드들 + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public int getPrice() { + return price; + } + + public String getImageUrl() { + return imageUrl; + } + + // setter 메서드들 + public void setId(Long id) { + this.id = id; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + // 주어진 Product 객체의 정보를 현재 객체에 업데이트하는 메서드 + public void updateFrom(Product product) { + this.name = product.getName(); + this.price = product.getPrice(); + this.imageUrl = product.getImageUrl(); + } + + // 객체를 문자열로 표현하는 메서드 + @Override + public String toString() { + return "Product{" + + "id=" + id + + ", name='" + name + '\'' + + ", price=" + price + + ", imageUrl='" + imageUrl + '\'' + + '}'; + } +} diff --git a/src/main/java/gift/model/ProductForm.java b/src/main/java/gift/model/ProductForm.java new file mode 100644 index 000000000..5fd06a6d4 --- /dev/null +++ b/src/main/java/gift/model/ProductForm.java @@ -0,0 +1,52 @@ +package gift.model; + +public class ProductForm { + + private String name; + private Integer price; + private String imageUrl; + + // 생성자 + public ProductForm(String name, Integer price, String imageUrl) { + this.name = name; + this.price = price; + this.imageUrl = imageUrl; + } + + // getter 메서드들 + public String getName() { + return name; + } + + public Integer getPrice() { + return price; + } + + public String getImageUrl() { + return imageUrl; + } + + // setter 메서드들 + public void setName(String name) { + this.name = name; + } + + public void setPrice(Integer price) { + this.price = price; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + + // 객체를 문자열로 표현하는 메서드 + @Override + public String toString() { + return "ProductForm{" + + "name='" + name + '\'' + + ", price=" + price + + ", imageUrl='" + imageUrl + '\'' + + '}'; + } + +} diff --git a/src/main/java/gift/repository/JdbcProductRepository.java b/src/main/java/gift/repository/JdbcProductRepository.java new file mode 100644 index 000000000..39b6d8df5 --- /dev/null +++ b/src/main/java/gift/repository/JdbcProductRepository.java @@ -0,0 +1,78 @@ +package gift.repository; + +import gift.model.Product; +import gift.model.ProductForm; +import java.util.List; +import java.util.Map; +import javax.sql.DataSource; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; + +public class JdbcProductRepository implements ProductRepository { + + private final JdbcTemplate jdbcTemplate; + + public JdbcProductRepository(DataSource dataSource) { + jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Override + public Product save(ProductForm form) { + SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate); + jdbcInsert.withTableName("product").usingGeneratedKeyColumns("id"); + + Map parameters = new HashMap<>(); + parameters.put("name", form.getName()); + parameters.put("price", form.getPrice()); + parameters.put("imageUrl", form.getImageUrl()); + + Number key = jdbcInsert.executeAndReturnKey(new MapSqlParameterSource(parameters)); + + Product product = new Product(); + product.setId(key.longValue()); // Number 타입에서 Long으로 변환하여 setId 호출 + product.setName(form.getName()); + product.setPrice(form.getPrice()); + product.setImageUrl(form.getImageUrl()); + + return product; + } + + @Override + public boolean delete(Long id) { + int update = jdbcTemplate.update("delete from product where id = ?", id); + return update != 0; + } + + @Override + public Product edit(Long id, ProductForm form) { + jdbcTemplate.update("update product set name = ?, price = ?, imageUrl = ? where id = ?", + form.getName(), form.getPrice(), form.getImageUrl(), id); + return findById(id); + } + + @Override + public Product findById(Long id) { + List result = jdbcTemplate.query("select * from product where id = ?", + productRowMapper(), id); + return result.stream().findFirst().orElse(null); + } + + @Override + public List findAll() { + return jdbcTemplate.query("select * from product", productRowMapper()); + } + + // RowMapper 구현 + private RowMapper productRowMapper() { + return (rs, rowNum) -> { + Product product = new Product(); + product.setId(rs.getLong("id")); + product.setName(rs.getString("name")); + product.setPrice(rs.getInt("price")); + product.setImageUrl(rs.getString("imageUrl")); + return product; + }; + } +} diff --git a/src/main/java/gift/repository/MemoryProductRepository.java b/src/main/java/gift/repository/MemoryProductRepository.java new file mode 100644 index 000000000..3541a6454 --- /dev/null +++ b/src/main/java/gift/repository/MemoryProductRepository.java @@ -0,0 +1,55 @@ +package gift.repository; + +import gift.model.Product; +import gift.model.ProductForm; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class MemoryProductRepository implements ProductRepository { + + private Map db = new HashMap<>(); + private static Long id = 0L; + + @Override + public Product save(Product product) { + product.setId(++id); // ID 증가 후 설정 + db.put(product.getId(), product); // Map에 제품 저장 + return product; + } + + @Override + public boolean delete(Long id) { + Product result = db.remove(id); // ID에 해당하는 제품 삭제 + return result != null; // 삭제 성공 여부 반환 + } + + @Override + public Product edit(Long id, ProductForm form) { + Product product = findById(id); // ID에 해당하는 제품 조회 + if (product == null) { + return null; // 제품이 없으면 null 반환 + } + // 제품 정보 수정 + product.setName(form.getName()); + product.setPrice(form.getPrice()); + product.setImageUrl(form.getImageUrl()); + return product; + } + + @Override + public Product findById(Long id) { + return db.get(id); // ID에 해당하는 제품 조회 + } + + @Override + public List findAll() { + return new ArrayList<>(db.values()); // 모든 제품 목록 반환 + } + + // 메모리 DB를 초기화하는 메서드 + public void clearDB() { + db.clear(); + } +} diff --git a/src/main/java/gift/repository/ProductRepository.java b/src/main/java/gift/repository/ProductRepository.java new file mode 100644 index 000000000..6a8845ac8 --- /dev/null +++ b/src/main/java/gift/repository/ProductRepository.java @@ -0,0 +1,48 @@ +package gift.repository; + +import gift.model.Product; +import gift.model.ProductForm; +import java.util.List; + +public interface ProductRepository { + + /** + * 제품 정보를 저장합니다. + * + * @param form 저장할 제품의 정보를 담고 있는 ProductForm 객체 + * @return 저장된 제품 객체 + */ + Product save(ProductForm form); + + /** + * 주어진 ID에 해당하는 제품을 삭제합니다. + * + * @param id 삭제할 제품의 ID + * @return 삭제 성공 여부를 나타내는 boolean 값 + */ + boolean delete(Long id); + + /** + * 주어진 ID에 해당하는 제품의 정보를 수정합니다. + * + * @param id 수정할 제품의 ID + * @param form 수정할 제품의 정보를 담고 있는 ProductForm 객체 + * @return 수정된 제품 객체 + */ + Product edit(Long id, ProductForm form); + + /** + * 주어진 ID에 해당하는 제품을 조회합니다. + * + * @param id 조회할 제품의 ID + * @return 조회된 제품 객체 + */ + Product findById(Long id); + + /** + * 데이터베이스에 저장된 모든 제품 목록을 조회합니다. + * + * @return 모든 제품의 목록을 담고 있는 List 객체 + */ + List findAll(); +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3d16b65f4..e16319a1d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,4 @@ spring.application.name=spring-gift +spring.datasource.url=jdbc:h2:tcp://localhost/~/test +spring.datasource.driver-class-name=org.h2.Driver +spring.datasource.username=sa \ No newline at end of file diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/resources/static/js/gotoPage.js b/src/main/resources/static/js/gotoPage.js new file mode 100644 index 000000000..9b1728ced --- /dev/null +++ b/src/main/resources/static/js/gotoPage.js @@ -0,0 +1,7 @@ +function gotoHome() { + window.location.href="http://localhost:8080/api/products/admin"; +} + +function gotoAdd() { + window.location.href="http://localhost:8080/api/products/admin/add"; +} \ No newline at end of file diff --git a/src/main/resources/templates/admin.html b/src/main/resources/templates/admin.html new file mode 100644 index 000000000..c86524ca3 --- /dev/null +++ b/src/main/resources/templates/admin.html @@ -0,0 +1,30 @@ + + + + admin + + + +
+ +
+ + + + + + + + + + + + + + +
idnamepriceimageUrl
+ detail +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/adminAdd.html b/src/main/resources/templates/adminAdd.html new file mode 100644 index 000000000..4043031ed --- /dev/null +++ b/src/main/resources/templates/adminAdd.html @@ -0,0 +1,58 @@ + + + + Add Product + + + +

Add Product

+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/src/main/resources/templates/adminDeleted.html b/src/main/resources/templates/adminDeleted.html new file mode 100644 index 000000000..f9b61abe5 --- /dev/null +++ b/src/main/resources/templates/adminDeleted.html @@ -0,0 +1,14 @@ + + + + Add Product + + + +

Successfully deleted

+
+ +
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/adminProductDetail.html b/src/main/resources/templates/adminProductDetail.html new file mode 100644 index 000000000..52e5ca4e5 --- /dev/null +++ b/src/main/resources/templates/adminProductDetail.html @@ -0,0 +1,66 @@ + + + + Add Product + + + +

Edit Product

+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html new file mode 100644 index 000000000..ddd8162d8 --- /dev/null +++ b/src/main/resources/templates/error.html @@ -0,0 +1,14 @@ + + + + Add Product + + + +

Error

+
+ +
+ + + \ No newline at end of file diff --git a/src/test/java/gift/repository/MemoryProductRepositoryTest.java b/src/test/java/gift/repository/MemoryProductRepositoryTest.java new file mode 100644 index 000000000..ec1d96648 --- /dev/null +++ b/src/test/java/gift/repository/MemoryProductRepositoryTest.java @@ -0,0 +1,82 @@ +package gift.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import gift.model.Product; +import gift.model.ProductForm; +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class MemoryProductRepositoryTest { + + MemoryProductRepository repository = new MemoryProductRepository(); + + @AfterEach + public void afterEach() { + repository.clearDB(); // 각 테스트 종료 후 메모리 데이터 초기화 + } + + @Test + public void save() { + // 제품 저장 테스트 + ProductForm productForm = new ProductForm("abc", 123, "www.test.com"); + Product savedProduct = repository.save(productForm); + + Product result = repository.findById(savedProduct.getId()); + + assertThat(result).isEqualTo(savedProduct); // 저장된 제품과 조회된 제품 비교 + } + + @Test + @DisplayName("존재하는 ID 삭제") + public void delete_exist() { + // 존재하는 제품 ID로 삭제 테스트 + ProductForm productForm = new ProductForm("abc", 123, "www.test.com"); + Product savedProduct = repository.save(productForm); + + boolean result = repository.delete(savedProduct.getId()); + + assertThat(result).isEqualTo(true); // 삭제 결과 검증 + } + + @Test + @DisplayName("존재하지 않는 ID 삭제") + public void delete_nonexistent() { + // 존재하지 않는 제품 ID로 삭제 시도 테스트 + ProductForm productForm = new ProductForm("abc", 123, "www.test.com"); + repository.save(productForm); + + boolean result = repository.delete(0L); + + assertThat(result).isEqualTo(false); // 삭제 결과 검증 + } + + @Test + public void edit() { + // 제품 정보 수정 테스트 + ProductForm productForm = new ProductForm("abc", 123, "www.test.com"); + Product savedProduct = repository.save(productForm); + + Product editedProduct = repository.edit(savedProduct.getId(), + new ProductForm("def", 123, "www.test.com")); + + assertThat(editedProduct).isNotNull(); // 수정된 제품이 null이 아님을 검증 + assertThat(editedProduct.getName()).isEqualTo("def"); // 수정된 제품의 이름 검증 + } + + @Test + public void findAll() { + // 모든 제품 조회 테스트 + ProductForm product1 = new ProductForm("abc", 123, "www.test1.com"); + ProductForm product2 = new ProductForm("def", 456, "www.test2.com"); + + repository.save(product1); + repository.save(product2); + + List result = repository.findAll(); + + assertThat(result.size()).isEqualTo(2); // 조회된 제품 목록의 크기 검증 + } +} diff --git a/src/test/java/gift/repository/ProductRepositoryIntegrationTest.java b/src/test/java/gift/repository/ProductRepositoryIntegrationTest.java new file mode 100644 index 000000000..c74c697dd --- /dev/null +++ b/src/test/java/gift/repository/ProductRepositoryIntegrationTest.java @@ -0,0 +1,89 @@ +package gift.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import gift.model.Product; +import gift.model.ProductForm; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; + +@SpringBootTest +@Transactional +public class ProductRepositoryIntegrationTest { + + @Autowired + ProductRepository productRepository; + + @Test + public void save() { + // 제품 저장 테스트 + ProductForm productForm = new ProductForm("abc", 123, "test.com"); + Product savedProduct = productRepository.save(productForm); + + // 저장된 제품 조회 + Product findProduct = productRepository.findById(savedProduct.getId()); + + // 저장된 제품과 조회된 제품 비교 + assertThat(findProduct.getName()).isEqualTo(productForm.getName()); + assertThat(findProduct.getPrice()).isEqualTo(productForm.getPrice()); + assertThat(findProduct.getImageUrl()).isEqualTo(productForm.getImageUrl()); + } + + @Test + public void delete() { + // 제품 삭제 테스트 + ProductForm productForm = new ProductForm("abc", 123, "test.com"); + Product savedProduct = productRepository.save(productForm); + + // 제품 삭제 + productRepository.delete(savedProduct.getId()); + + // 삭제된 제품 조회 + Product findProduct = productRepository.findById(savedProduct.getId()); + + // 삭제된 제품이 null인지 검증 + assertThat(findProduct).isNull(); + } + + @Test + public void edit() { + // 제품 수정 테스트 + ProductForm productForm = new ProductForm("abc", 123, "test.com"); + Product savedProduct = productRepository.save(productForm); + + // 수정할 제품 정보 설정 + ProductForm editProductForm = new ProductForm("def", productForm.getPrice(), + productForm.getImageUrl()); + + // 제품 수정 + Product editedProduct = productRepository.edit(savedProduct.getId(), editProductForm); + + // 수정된 제품 조회 + Product findProduct = productRepository.findById(savedProduct.getId()); + + // 수정된 제품의 이름이 예상과 일치하는지 검증 + assertThat(findProduct.getName()).isEqualTo(editedProduct.getName()); + } + + @Test + public void findAll() { + // 모든 제품 조회 테스트 + ProductForm product1 = new ProductForm("abc", 123, "test1.com"); + ProductForm product2 = new ProductForm("def", 234, "test2.com"); + ProductForm product3 = new ProductForm("ghi", 345, "test3.com"); + + // 제품 저장 + productRepository.save(product1); + productRepository.save(product2); + productRepository.save(product3); + + // 모든 제품 조회 + List allProducts = productRepository.findAll(); + + // 조회된 제품 목록의 크기 검증 + assertThat(allProducts.size()).isEqualTo(3); + } +}