From dc6fb0464c91f742d7987053f260a0e6d99c396c Mon Sep 17 00:00:00 2001 From: kiblykat Date: Sun, 24 Mar 2024 22:56:42 +0800 Subject: [PATCH 1/6] SIS-34:removed explicit customerId definition in Review since FK --- .../com/smartinventory/entities/Review.java | 21 +++++--- .../serviceImpls/ReviewServiceImpl.java | 1 - .../smartinventory/utility/DataLoader.java | 53 ++++++++++++------- .../controllers/ReviewControllerTest.java | 2 +- .../services/ReviewServiceImplTest.java | 2 +- 5 files changed, 48 insertions(+), 31 deletions(-) diff --git a/src/main/java/sg/com/smartinventory/entities/Review.java b/src/main/java/sg/com/smartinventory/entities/Review.java index 6d38719..0b44247 100644 --- a/src/main/java/sg/com/smartinventory/entities/Review.java +++ b/src/main/java/sg/com/smartinventory/entities/Review.java @@ -1,10 +1,13 @@ package sg.com.smartinventory.entities; +import com.fasterxml.jackson.annotation.JsonBackReference; + import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.Min; @@ -35,14 +38,19 @@ public class Review { @Column(name = "rating") private int rating; - @Min(value = 1, message = "Customer ID should start from 1. ") - @Column(name = "customer_id") - private long customerId; // FK. PostgreSQL bigserial data type. - @Min(value = 1, message = "Product ID should start from 1. ") @Column(name = "product_id") private long productId; // FK. PostgreSQL bigserial data type. + // @ManyToOne Customer -> Many Reviews can be linked to 1 Customer + // @Min(value = 1, message = "Customer ID should start from 1. ") + @JsonBackReference + @ManyToOne(optional = false) + @JoinColumn(name = "customer_id", referencedColumnName = "id") + private Customer customer; + + // @ManyToOne Product -> Many Reviews can be linked to 1 Product + public Review() { } @@ -53,11 +61,8 @@ public Review(String category, String reviewContent, int rating, long customerId this.category = category; this.reviewContent = reviewContent; this.rating = rating; - this.customerId = customerId; + // this.customerId = customerId; this.productId = productId; } - // @ManyToOne Product -> Many Reviews can be linked to 1 Product - - // @ManyToOne Customer -> Many Reviews can be linked to 1 Customer } \ No newline at end of file diff --git a/src/main/java/sg/com/smartinventory/serviceImpls/ReviewServiceImpl.java b/src/main/java/sg/com/smartinventory/serviceImpls/ReviewServiceImpl.java index 8c51149..9d4d736 100644 --- a/src/main/java/sg/com/smartinventory/serviceImpls/ReviewServiceImpl.java +++ b/src/main/java/sg/com/smartinventory/serviceImpls/ReviewServiceImpl.java @@ -52,7 +52,6 @@ public Review updateReview(Long id, Review review) { reviewToUpdate.setCategory(review.getCategory()); reviewToUpdate.setReviewContent(review.getReviewContent()); reviewToUpdate.setRating(review.getRating()); - reviewToUpdate.setCustomerId(review.getCustomerId()); reviewToUpdate.setProductId(review.getProductId()); // Save the updated review back to the database. diff --git a/src/main/java/sg/com/smartinventory/utility/DataLoader.java b/src/main/java/sg/com/smartinventory/utility/DataLoader.java index 38493b7..3c96d71 100644 --- a/src/main/java/sg/com/smartinventory/utility/DataLoader.java +++ b/src/main/java/sg/com/smartinventory/utility/DataLoader.java @@ -57,25 +57,38 @@ public void loadData() { productRepository.save(new Product("Books", "Science Fiction Novel", "Bestselling sci-fi novel set in a dystopian future. ", 14.99, 300)); - reviewRepository.save(new Review("Books", "Expected more from the ending, felt rushed. ", - 3, 1, 1)); - reviewRepository.save(new Review("Electronics", "Fast delivery, product works as expected. ", - 4, 1, 2)); - reviewRepository.save(new Review("Clothing", "Very comfortable t-shirt, fits perfectly. ", - 4, 2, 2)); - reviewRepository.save(new Review("Home & Kitchen", "Difficult to assemble, but sturdy once done. ", - 3, 2, 4)); - reviewRepository.save(new Review("Electronics", "Great smartphone with excellent features. ", - 5, 3, 1)); - reviewRepository.save(new Review("Clothing", "The color faded after a few washes. ", - 2, 3, 3)); - reviewRepository.save(new Review("Beauty", "Lovely fragrance, long-lasting. ", - 5, 4, 4)); - reviewRepository.save(new Review("Home & Kitchen", "Makes delicious coffee, easy to use. ", - 4, 4, 3)); - reviewRepository.save(new Review("Books", "Intriguing plot, couldn't put it down. ", - 5, 5, 5)); - reviewRepository.save(new Review("Beauty", "Disappointed with the scent, doesn't last long. ", - 2, 5, 5)); + // - - - NOTE: DATALOADER DONT WORK FOR ENTITIES WITH FK* (cant specify + // customer_id) - - - + + // reviewRepository.save(new Review("Books", "Expected more from the ending, + // felt rushed. ", + // 3, 1, 1)); + // reviewRepository.save(new Review("Electronics", "Fast delivery, product works + // as expected. ", + // 4, 1, 2)); + // reviewRepository.save(new Review("Clothing", "Very comfortable t-shirt, fits + // perfectly. ", + // 4, 2, 2)); + // reviewRepository.save(new Review("Home & Kitchen", "Difficult to assemble, + // but sturdy once done. ", + // 3, 2, 4)); + // reviewRepository.save(new Review("Electronics", "Great smartphone with + // excellent features. ", + // 5, 3, 1)); + // reviewRepository.save(new Review("Clothing", "The color faded after a few + // washes. ", + // 2, 3, 3)); + // reviewRepository.save(new Review("Beauty", "Lovely fragrance, long-lasting. + // ", + // 5, 4, 4)); + // reviewRepository.save(new Review("Home & Kitchen", "Makes delicious coffee, + // easy to use. ", + // 4, 4, 3)); + // reviewRepository.save(new Review("Books", "Intriguing plot, couldn't put it + // down. ", + // 5, 5, 5)); + // reviewRepository.save(new Review("Beauty", "Disappointed with the scent, + // doesn't last long. ", + // 2, 5, 5)); } } \ No newline at end of file diff --git a/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java b/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java index 92c140f..621aa6a 100644 --- a/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java +++ b/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java @@ -64,7 +64,7 @@ public void createReviewTest() throws Exception { // Step 1: Create a Review object Review newReview = Review.builder().category("Electronics") - .reviewContent("Great smartphone with excellent features. ").rating(5).customerId(1) + .reviewContent("Great smartphone with excellent features. ").rating(5) .productId(2).build(); // Step 2: Convert the Java object to JSON using ObjectMapper. diff --git a/src/test/java/sg/com/smartinventory/services/ReviewServiceImplTest.java b/src/test/java/sg/com/smartinventory/services/ReviewServiceImplTest.java index 6d85aac..9a0d44e 100644 --- a/src/test/java/sg/com/smartinventory/services/ReviewServiceImplTest.java +++ b/src/test/java/sg/com/smartinventory/services/ReviewServiceImplTest.java @@ -56,7 +56,7 @@ public void createReviewTest() { // 1. SETUP // Create a new review. Review review = Review.builder().category("Electronics") - .reviewContent("Great smartphone with excellent features. ").rating(5).customerId(1) + .reviewContent("Great smartphone with excellent features. ").rating(5) .productId(2).build(); // Mock the save method of the review repository. From 6d42d40055251eaa5fa46489ed9650010b9e53c4 Mon Sep 17 00:00:00 2001 From: kiblykat Date: Sun, 24 Mar 2024 23:00:14 +0800 Subject: [PATCH 2/6] SIS-35: added /search and customer/{id}/reviews endpoints --- .../controllers/CustomerController.java | 18 ++++++++-- .../com/smartinventory/entities/Customer.java | 16 ++------- .../repositories/CustomerRepository.java | 2 +- .../serviceImpls/CustomerServiceImpl.java | 35 ++++++++++++++----- .../services/CustomerService.java | 5 +++ 5 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/main/java/sg/com/smartinventory/controllers/CustomerController.java b/src/main/java/sg/com/smartinventory/controllers/CustomerController.java index 19ed27c..3c0735c 100644 --- a/src/main/java/sg/com/smartinventory/controllers/CustomerController.java +++ b/src/main/java/sg/com/smartinventory/controllers/CustomerController.java @@ -15,6 +15,7 @@ import jakarta.validation.Valid; import sg.com.smartinventory.entities.Customer; +import sg.com.smartinventory.entities.Review; // import sg.com.smartinventory.entities.Review; import sg.com.smartinventory.services.CustomerService; @@ -45,6 +46,13 @@ public ResponseEntity createCustomer(@Valid @RequestBody Customer cust return new ResponseEntity<>(newCustomer, HttpStatus.CREATED); } + @PostMapping("/{id}/reviews") + public ResponseEntity addReviewToCustomer(@PathVariable long id, @RequestBody Review review) { + // TODO: process POST request + Review newReview = customerService.addReviewToCustomer(id, review); + return new ResponseEntity<>(newReview, HttpStatus.OK); + } + // READ (all) @GetMapping("") public ResponseEntity> getAllCustomers() { @@ -59,10 +67,16 @@ public ResponseEntity getCustomer(@PathVariable long id) { return new ResponseEntity<>(foundCustomer, HttpStatus.OK); } + // READ (by name CONTAINS) + @GetMapping("/search") + public ResponseEntity> searchCustomer(@RequestParam String firstName) { + ArrayList customers = customerService.searchCustomer(firstName); + return new ResponseEntity<>(customers, HttpStatus.OK); + } + // UPDATE @PutMapping("/{id}") public ResponseEntity updateCustomer(@PathVariable long id, @RequestBody Customer customer) { - // TODO: process PUT request Customer updatedCustomer = customerService.updateCustomer(id, customer); return new ResponseEntity<>(updatedCustomer, HttpStatus.OK); } @@ -71,7 +85,7 @@ public ResponseEntity updateCustomer(@PathVariable long id, @RequestBo @DeleteMapping("/{id}") public ResponseEntity deleteCustomer(@PathVariable long id) { customerService.deleteCustomer(id); - return new ResponseEntity<>(HttpStatus.NOT_FOUND); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); } // // Nested route - Add review to customer. diff --git a/src/main/java/sg/com/smartinventory/entities/Customer.java b/src/main/java/sg/com/smartinventory/entities/Customer.java index 1e20a2b..4e1a5bb 100644 --- a/src/main/java/sg/com/smartinventory/entities/Customer.java +++ b/src/main/java/sg/com/smartinventory/entities/Customer.java @@ -60,25 +60,15 @@ public class Customer { @Column(name = "email") private String email; - // Uni-directional One to Many mapping -> One Customer (Parent) can have many - // Reviews (Child). The extra column 'customer_id' will be created on the many - // side of the relationship, that is, in the Review table. The cascade attribute - // is set to CascadeType.ALL to cascade all operations (e.g., save, update, - // delete) to the associated Review entities. The @JoinColumn annotation is used - // to specify the foreign key column (customer_id) in the Review table that - // establishes the relationship. Thus, it specifies the foreign key column in - // the child entity’s table that refers to the parent entity. The ‘mappedBy’ - // attribute is not used in a unidirectional relationship as it’s specific to - // bidirectional relationships. - @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) - @JoinColumn(name = "customer_id", referencedColumnName = "id") + @OneToMany(mappedBy = "customer") private List reviews; public Customer() { } // Define Constructor for DataLoader. - public Customer(String firstName, String lastName, String country, String address, int postalCode, int phoneNumber, + public Customer(String firstName, String lastName, String country, String address, int postalCode, + int phoneNumber, String email) { this(); diff --git a/src/main/java/sg/com/smartinventory/repositories/CustomerRepository.java b/src/main/java/sg/com/smartinventory/repositories/CustomerRepository.java index 50c89f1..7c4a062 100644 --- a/src/main/java/sg/com/smartinventory/repositories/CustomerRepository.java +++ b/src/main/java/sg/com/smartinventory/repositories/CustomerRepository.java @@ -14,7 +14,7 @@ public interface CustomerRepository extends JpaRepository { // List findById(long id); // Custom query to find all customers with a certain first name. - List findByFirstName(String firstName); + List findByFirstNameContaining(String firstName); // Custom query to find all customers with a certain last name. List findByLastName(String lastName); diff --git a/src/main/java/sg/com/smartinventory/serviceImpls/CustomerServiceImpl.java b/src/main/java/sg/com/smartinventory/serviceImpls/CustomerServiceImpl.java index b6b2f15..9e5c903 100644 --- a/src/main/java/sg/com/smartinventory/serviceImpls/CustomerServiceImpl.java +++ b/src/main/java/sg/com/smartinventory/serviceImpls/CustomerServiceImpl.java @@ -6,35 +6,41 @@ import org.springframework.stereotype.Service; import sg.com.smartinventory.entities.Customer; +import sg.com.smartinventory.entities.Review; // import sg.com.smartinventory.entities.Review; import sg.com.smartinventory.exceptions.CustomerNotFoundException; import sg.com.smartinventory.repositories.CustomerRepository; +import sg.com.smartinventory.repositories.ReviewRepository; import sg.com.smartinventory.services.CustomerService; @Service public class CustomerServiceImpl implements CustomerService { private CustomerRepository customerRepository; + private ReviewRepository reviewRepository; // @Autowired - public CustomerServiceImpl(CustomerRepository customerRepository) { + public CustomerServiceImpl(CustomerRepository customerRepository, ReviewRepository reviewRepository) { this.customerRepository = customerRepository; + this.reviewRepository = reviewRepository; } + // - - - POST METHODS @Override public Customer createCustomer(Customer customer) { Customer newCustomer = customerRepository.save(customer); - return newCustomer; } + public Review addReviewToCustomer(long id, Review review) { + Customer customer = customerRepository.findById(id).orElseThrow(() -> new CustomerNotFoundException(id)); + review.setCustomer(customer); + Review newReview = reviewRepository.save(review); + return newReview; + } + + // - - - GET METHODS @Override public Customer getCustomer(Long id) { - // Optional optionalCustomer = customerRepository.findById(id); - // if(optionalCustomer.isPresent()) { - // Customer foundCustomer = optionalCustomer.get(); - // return foundCustomer; - // } - // throw new CustomerNotFoundException(id); return customerRepository.findById(id).orElseThrow(() -> new CustomerNotFoundException(id)); } @@ -44,6 +50,14 @@ public ArrayList getAllCustomers() { return (ArrayList) allCustomers; } + // searches for first name that contains search term + @Override + public ArrayList searchCustomer(String firstName) { + List customers = customerRepository.findByFirstNameContaining(firstName); + return (ArrayList) customers; + } + + // - - - PUT METHODS @Override public Customer updateCustomer(Long id, Customer customer) { // Retrieve the customer from the database. @@ -63,8 +77,13 @@ public Customer updateCustomer(Long id, Customer customer) { return customerRepository.save(customerToUpdate); } + // - - - DELETE METHODS @Override public void deleteCustomer(long id) { + // findById method allows deleteCustomer to throw exception if no id of + // such type is avail to be deleted i.e response will be 404 (Expected) instead + // of 204, to tell client that resource not found + customerRepository.findById(id).orElseThrow(() -> new CustomerNotFoundException(id)); customerRepository.deleteById(id); } diff --git a/src/main/java/sg/com/smartinventory/services/CustomerService.java b/src/main/java/sg/com/smartinventory/services/CustomerService.java index 60d536c..59bff4a 100644 --- a/src/main/java/sg/com/smartinventory/services/CustomerService.java +++ b/src/main/java/sg/com/smartinventory/services/CustomerService.java @@ -4,12 +4,17 @@ import sg.com.smartinventory.entities.Customer; // import sg.com.smartinventory.entities.Review; +import sg.com.smartinventory.entities.Review; public interface CustomerService { Customer createCustomer(Customer customer); + Review addReviewToCustomer(long id, Review review); + Customer getCustomer(Long id); + ArrayList searchCustomer(String name); + ArrayList getAllCustomers(); Customer updateCustomer(Long id, Customer customer); From 4192d53556675299b597953d0c7b50f433b89ee8 Mon Sep 17 00:00:00 2001 From: izzat Date: Mon, 25 Mar 2024 23:32:36 +0800 Subject: [PATCH 3/6] SIS-38: Update DataLoader to include foreign key references based on Bean injection --- .../controllers/ReviewController.java | 12 +- .../com/smartinventory/entities/Customer.java | 3 +- .../com/smartinventory/entities/Product.java | 6 +- .../com/smartinventory/entities/Review.java | 6 +- .../smartinventory/utility/DataLoader.java | 107 ++++++++++-------- 5 files changed, 74 insertions(+), 60 deletions(-) diff --git a/src/main/java/sg/com/smartinventory/controllers/ReviewController.java b/src/main/java/sg/com/smartinventory/controllers/ReviewController.java index 2681a6a..40dde6d 100644 --- a/src/main/java/sg/com/smartinventory/controllers/ReviewController.java +++ b/src/main/java/sg/com/smartinventory/controllers/ReviewController.java @@ -27,16 +27,8 @@ public ReviewController(ReviewService reviewService) { this.reviewService = reviewService; } - // CREATE. - @PostMapping("") - public ResponseEntity createReview(@Valid @RequestBody Review review) { - // if(bindingResult.hasErrors()) { - // return new ResponseEntity<>(HttpStatus.BAD_REQUEST); - // } - - Review newReview = reviewService.createReview(review); - return new ResponseEntity<>(newReview, HttpStatus.CREATED); - } + // - - - NO POST HERE, due to data integrity with Customer FK - - - + // @PostMapping("")... // READ (GET ALL). @GetMapping("") diff --git a/src/main/java/sg/com/smartinventory/entities/Customer.java b/src/main/java/sg/com/smartinventory/entities/Customer.java index 4e1a5bb..f10b601 100644 --- a/src/main/java/sg/com/smartinventory/entities/Customer.java +++ b/src/main/java/sg/com/smartinventory/entities/Customer.java @@ -60,7 +60,8 @@ public class Customer { @Column(name = "email") private String email; - @OneToMany(mappedBy = "customer") + @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL) + private List reviews; public Customer() { diff --git a/src/main/java/sg/com/smartinventory/entities/Product.java b/src/main/java/sg/com/smartinventory/entities/Product.java index da07a29..fbcde3c 100644 --- a/src/main/java/sg/com/smartinventory/entities/Product.java +++ b/src/main/java/sg/com/smartinventory/entities/Product.java @@ -55,9 +55,9 @@ public class Product { // the child entity’s table that refers to the parent entity. The ‘mappedBy’ // attribute is not used in a unidirectional relationship as it’s specific to // bidirectional relationships. - @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) - @JoinColumn(name = "product_id", referencedColumnName = "id") - private List reviews; + // @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + // @JoinColumn(name = "product_id", referencedColumnName = "id") + // private List reviews; public Product() { } diff --git a/src/main/java/sg/com/smartinventory/entities/Review.java b/src/main/java/sg/com/smartinventory/entities/Review.java index 0b44247..a21f04c 100644 --- a/src/main/java/sg/com/smartinventory/entities/Review.java +++ b/src/main/java/sg/com/smartinventory/entities/Review.java @@ -1,5 +1,7 @@ package sg.com.smartinventory.entities; +import org.springframework.stereotype.Component; + import com.fasterxml.jackson.annotation.JsonBackReference; import jakarta.persistence.Column; @@ -17,6 +19,7 @@ import lombok.Getter; import lombok.Setter; +@Component // @Component annotation required to inject into DataLoader @Getter @Setter @Builder @@ -38,7 +41,7 @@ public class Review { @Column(name = "rating") private int rating; - @Min(value = 1, message = "Product ID should start from 1. ") + // @Min(value = 1, message = "Product ID should start from 1. ") @Column(name = "product_id") private long productId; // FK. PostgreSQL bigserial data type. @@ -50,6 +53,7 @@ public class Review { private Customer customer; // @ManyToOne Product -> Many Reviews can be linked to 1 Product + // TODO public Review() { } diff --git a/src/main/java/sg/com/smartinventory/utility/DataLoader.java b/src/main/java/sg/com/smartinventory/utility/DataLoader.java index 3c96d71..7601ab1 100644 --- a/src/main/java/sg/com/smartinventory/utility/DataLoader.java +++ b/src/main/java/sg/com/smartinventory/utility/DataLoader.java @@ -18,13 +18,15 @@ public class DataLoader { private CustomerRepository customerRepository; private ProductRepository productRepository; private ReviewRepository reviewRepository; + private Review review; // @Autowired public DataLoader(CustomerRepository customerRepository, ProductRepository productRepository, - ReviewRepository reviewRepository) { + ReviewRepository reviewRepository, Review review) { this.customerRepository = customerRepository; this.productRepository = productRepository; this.reviewRepository = reviewRepository; + this.review = review; } @PostConstruct @@ -34,18 +36,63 @@ public void loadData() { productRepository.deleteAll(); reviewRepository.deleteAll(); - // Create fake data. - customerRepository.save(new Customer("John", "Doe", "USA", "123 Main St", 123456, 12345678, - "john.doe@example.com")); - customerRepository.save(new Customer("Alice", "Smith", "Canada", "456 Maple Ave", 543210, 98765432, - "alice.smith@example.com")); - customerRepository.save(new Customer("Michael", "Johnson", "UK", "789 Oak Rd", 567890, 98761234, - "michael.johnson@example.com")); - customerRepository.save(new Customer("Emily", "Brown", "Australia", "321 Elm St", 135790, 45678912, - "emily.brown@example.com")); - customerRepository.save(new Customer("David", "Wilson", "Germany", "654 Pine Rd", 987655, 36985214, - "david.wilson@example.com")); + // = = = CUSTOMER DATA = = = + Customer customer1 = customerRepository + .save(new Customer("John", "Doe", "USA", "123 Main St", 123456, 12345678, + "john.doe@example.com")); + Customer customer2 = customerRepository + .save(new Customer("Alice", "Smith", "Canada", "456 Maple Ave", 543210, 98765432, + "alice.smith@example.com")); + Customer customer3 = customerRepository + .save(new Customer("Michael", "Johnson", "UK", "789 Oak Rd", 567890, 98761234, + "michael.johnson@example.com")); + Customer customer4 = customerRepository + .save(new Customer("Emily", "Brown", "Australia", "321 Elm St", 135790, 45678912, + "emily.brown@example.com")); + Customer customer5 = customerRepository + .save(new Customer("David", "Wilson", "Germany", "654 Pine Rd", 987655, 36985214, + "david.wilson@example.com")); + // = = = REVIEW DATA = = = + // Adding review data (note that the "same" review object is being used in all, + // this is because of Bean injection so its actually diff instances) + Review review = new Review("Books", "Expected more from the ending, felt rushed. ", 3, 1, 1); + review.setCustomer(customer1); + reviewRepository.save(review); + + review = new Review("Electronics", "Fast delivery, product works as expected. ", 4, 1, 2); + review.setCustomer(customer2); + reviewRepository.save(review); + + review = new Review("Home & Kitchen", "Difficult to assemble, but sturdy once done. ", 3, 2, 4); + review.setCustomer(customer3); + reviewRepository.save(review); + + review = new Review("Electronics", "Great smartphone with excellent features. ", 5, 3, 1); + review.setCustomer(customer4); + reviewRepository.save(review); + + review = new Review("Clothing", "The color faded after a few washes. ", 2, 3, 3); + review.setCustomer(customer5); + reviewRepository.save(review); + + review = (new Review("Beauty", "Lovely fragrance, long-lasting. ", 5, 4, 4)); + review.setCustomer(customer1); + reviewRepository.save(review); + + review = (new Review("Home & Kitchen", "Makes delicious coffee, easy to use. ", 4, 4, 3)); + review.setCustomer(customer2); + reviewRepository.save(review); + + review = (new Review("Books", "Intriguing plot, couldn't put it down. ", 5, 5, 5)); + review.setCustomer(customer3); + reviewRepository.save(review); + + review = (new Review("Beauty", "Disappointed with the scent, doesn't last long. ", 2, 5, 5)); + review.setCustomer(customer4); + reviewRepository.save(review); + + // = = = PRODUCT = = = productRepository.save(new Product("Electronics", "Smartphone", "High-end smartphone with advanced features. ", 999.99, 100)); productRepository.save(new Product("Clothing", "Men's T-Shirt", @@ -57,38 +104,8 @@ public void loadData() { productRepository.save(new Product("Books", "Science Fiction Novel", "Bestselling sci-fi novel set in a dystopian future. ", 14.99, 300)); - // - - - NOTE: DATALOADER DONT WORK FOR ENTITIES WITH FK* (cant specify - // customer_id) - - - - - // reviewRepository.save(new Review("Books", "Expected more from the ending, - // felt rushed. ", - // 3, 1, 1)); - // reviewRepository.save(new Review("Electronics", "Fast delivery, product works - // as expected. ", - // 4, 1, 2)); - // reviewRepository.save(new Review("Clothing", "Very comfortable t-shirt, fits - // perfectly. ", - // 4, 2, 2)); - // reviewRepository.save(new Review("Home & Kitchen", "Difficult to assemble, - // but sturdy once done. ", - // 3, 2, 4)); - // reviewRepository.save(new Review("Electronics", "Great smartphone with - // excellent features. ", - // 5, 3, 1)); - // reviewRepository.save(new Review("Clothing", "The color faded after a few - // washes. ", - // 2, 3, 3)); - // reviewRepository.save(new Review("Beauty", "Lovely fragrance, long-lasting. - // ", - // 5, 4, 4)); - // reviewRepository.save(new Review("Home & Kitchen", "Makes delicious coffee, - // easy to use. ", - // 4, 4, 3)); - // reviewRepository.save(new Review("Books", "Intriguing plot, couldn't put it - // down. ", - // 5, 5, 5)); - // reviewRepository.save(new Review("Beauty", "Disappointed with the scent, - // doesn't last long. ", - // 2, 5, 5)); + // = = = NOTE: DATALOADER DONT WORK FOR ENTITIES WITH FK* (cant specify + // customer_id column) = = = + } } \ No newline at end of file From 90c6a8fc8b69455a2905c4e4685e06a85419c600 Mon Sep 17 00:00:00 2001 From: izzat Date: Mon, 25 Mar 2024 23:44:39 +0800 Subject: [PATCH 4/6] SIS-39: Fix Test Cases due to new @ManyToOne relationship --- .../controllers/CustomerControllerTest.java | 5 + .../controllers/ReviewControllerTest.java | 113 ++++++++++++------ 2 files changed, 79 insertions(+), 39 deletions(-) diff --git a/src/test/java/sg/com/smartinventory/controllers/CustomerControllerTest.java b/src/test/java/sg/com/smartinventory/controllers/CustomerControllerTest.java index ac43068..bcaffb1 100644 --- a/src/test/java/sg/com/smartinventory/controllers/CustomerControllerTest.java +++ b/src/test/java/sg/com/smartinventory/controllers/CustomerControllerTest.java @@ -79,4 +79,9 @@ public void createCustomerTest() throws Exception { test_logger.info("Ending test: " + getCurrentMethodName() + ". "); } + + @DisplayName("Create Customer") + @Test + public void addReviewToCustomerTest() throws Exception { + } } \ No newline at end of file diff --git a/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java b/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java index 621aa6a..d63ab29 100644 --- a/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java +++ b/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java @@ -3,14 +3,15 @@ import static sg.com.smartinventory.utility.Utility.*; import static org.junit.jupiter.api.Assertions.*; - +import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; - +import org.mockito.InjectMocks; +import org.mockito.Mock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,7 +25,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; +import sg.com.smartinventory.entities.Customer; import sg.com.smartinventory.entities.Review; +import sg.com.smartinventory.repositories.ReviewRepository; +import sg.com.smartinventory.serviceImpls.ReviewServiceImpl; @SpringBootTest @AutoConfigureMockMvc @@ -52,45 +56,76 @@ void teardown() { } - /** - * Test the creation of a Review. - * - * @throws Exception - */ - @DisplayName("Create Review") + @Mock + private ReviewRepository reviewRepository; + + @InjectMocks + private ReviewServiceImpl reviewService; + @Test - public void createReviewTest() throws Exception { - test_logger.info("Starting test: " + getCurrentMethodName() + ". "); - - // Step 1: Create a Review object - Review newReview = Review.builder().category("Electronics") - .reviewContent("Great smartphone with excellent features. ").rating(5) - .productId(2).build(); - - // Step 2: Convert the Java object to JSON using ObjectMapper. - String newReviewAsJSON = objectMapper.writeValueAsString(newReview); - - // Step 3: Build the request. - RequestBuilder request = MockMvcRequestBuilders.post("/reviews") - .contentType(MediaType.APPLICATION_JSON) - .content(newReviewAsJSON); - - // Step 4: Perform the request and get the response and assert. - mockMvc.perform(request) - // MvcResult Result = mockMvc.perform(request) - // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) - .andExpect(status().isCreated()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.category").value("Electronics")) - .andExpect(jsonPath("$.rating").value(5)); - // .andDo(print -> test_logger.error("Customer's id: {}", - // print.getResponse().getContentAsString())) - // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) - // .andReturn(); + @DisplayName("Get Review Test by Id") + public void getReviewTest() throws Exception { + // Setup + // for now, setup is created in DataLoader. need fix + + // Build the GET request + RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/reviews/2"); - // Review ReviewObject = fromJsonResult(Result, Review.class); + // when(reviewService.getReview(2L)).thenReturn(testReview); - // test_logger.error("Ending test: createReviewTest. "); - test_logger.info("Ending test: " + getCurrentMethodName() + ". "); + // Perform the request (Execute + Assert) + mockMvc.perform(requestBuilder) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.id").value(2)); } + // = = = DATA INTEGRITY VIOLATION EXCEPTION = = = + // /** + // * Test the creation of a Review. + // * + // * @throws Exception + // */ + // @DisplayName("Create Review") + // @Test + // public void createReviewTest() throws Exception { + // test_logger.info("Starting test: " + getCurrentMethodName() + ". "); + + // Customer customer = + // Customer.builder().firstName("John").lastName("Doe").country("USA") + // .address("123 Main St").postalCode(123456).phoneNumber(12345678) + // .email("john.doe@example.com").build(); + + // // Step 1: Create a Review object + // Review newReview = Review.builder().category("Electronics") + // .reviewContent("Great smartphone with excellent features. ").rating(5) + // .productId(2).build(); + + // newReview.setCustomer(customer); + + // // Step 2: Convert the Java object to JSON using ObjectMapper. + // String newReviewAsJSON = objectMapper.writeValueAsString(newReview); + + // // Step 3: Build the request. + // RequestBuilder request = MockMvcRequestBuilders.post("/reviews") + // .contentType(MediaType.APPLICATION_JSON) + // .content(newReviewAsJSON); + + // // Step 4: Perform the request and get the response and assert. + // mockMvc.perform(request) + // // MvcResult Result = mockMvc.perform(request) + // // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) + // .andExpect(status().isCreated()) + // .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + // .andExpect(jsonPath("$.category").value("Electronics")) + // .andExpect(jsonPath("$.rating").value(5)); + // // .andDo(print -> test_logger.error("Customer's id: {}", + // // print.getResponse().getContentAsString())) + // // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) + // // .andReturn(); + + // // Review ReviewObject = fromJsonResult(Result, Review.class); + + // // test_logger.error("Ending test: createReviewTest. "); + // test_logger.info("Ending test: " + getCurrentMethodName() + ". "); + // } } From 268a1b892d17ed90aa380d462de81a83b1c985e1 Mon Sep 17 00:00:00 2001 From: Izzat Fadzlon <52589461+kiblykat@users.noreply.github.com> Date: Tue, 26 Mar 2024 00:06:11 +0800 Subject: [PATCH 5/6] Update ReviewControllerTest.java --- .../controllers/ReviewControllerTest.java | 238 +++++++++--------- 1 file changed, 119 insertions(+), 119 deletions(-) diff --git a/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java b/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java index 8acdef4..eefa75a 100644 --- a/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java +++ b/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java @@ -125,124 +125,124 @@ public void createReviewTest() throws Exception { //<<<<<<< SIS-39 // ======= - @DisplayName("Get All Reviews") - @Test - public void getAllReviewsTest() throws Exception { - test_logger.info("Starting test: " + getCurrentMethodName() + ". "); - - // Step 1: Create a Review objects. - Review newReview = Review.builder().category("Electronics") - .reviewContent("Great smartphone with excellent features. ").rating(5).customerId(1) - .productId(2).build(); - - // Step 2: Convert the Java object to JSON using ObjectMapper. - String newReviewAsJSON = objectMapper.writeValueAsString(newReview); - - // Step 3: Build the request. - RequestBuilder request = MockMvcRequestBuilders.post("/reviews") - .contentType(MediaType.APPLICATION_JSON) - .content(newReviewAsJSON); - - // Step 4: Perform the request and get the response and assert. - mockMvc.perform(request) - // MvcResult Result = mockMvc.perform(request) - // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) - .andExpect(status().isCreated()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.category").value("Electronics")) - .andExpect(jsonPath("$.rating").value(5)); - - test_logger.info("Ending test: " + getCurrentMethodName() + ". "); - } - - @DisplayName("Get One Review") - @Test - public void getOneReviewTest() throws Exception { - test_logger.info("Starting test: " + getCurrentMethodName() + ". "); - - // Step 1: Create a Review object. - Review newReview = Review.builder().category("Electronics") - .reviewContent("Great smartphone with excellent features. ").rating(5).customerId(1) - .productId(2).build(); - - // Step 2: Convert the Java object to JSON using ObjectMapper. - String newReviewAsJSON = objectMapper.writeValueAsString(newReview); - - // Step 3: Build the request. - RequestBuilder request = MockMvcRequestBuilders.post("/reviews") - .contentType(MediaType.APPLICATION_JSON) - .content(newReviewAsJSON); - - // Step 4: Perform the request and get the response and assert. - mockMvc.perform(request) - // MvcResult Result = mockMvc.perform(request) - // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) - .andExpect(status().isCreated()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.category").value("Electronics")) - .andExpect(jsonPath("$.rating").value(5)); - - test_logger.info("Ending test: " + getCurrentMethodName() + ". "); - } - - @DisplayName("Update Review") - @Test - public void updateReviewTest() throws Exception { - test_logger.info("Starting test: " + getCurrentMethodName() + ". "); - - // Step 1: Create a Review object. - Review newReview = Review.builder().category("Electronics") - .reviewContent("Great smartphone with excellent features. ").rating(5).customerId(1) - .productId(2).build(); - - // Step 2: Convert the Java object to JSON using ObjectMapper. - String newReviewAsJSON = objectMapper.writeValueAsString(newReview); - - // Step 3: Build the request. - RequestBuilder request = MockMvcRequestBuilders.post("/reviews") - .contentType(MediaType.APPLICATION_JSON) - .content(newReviewAsJSON); - - // Step 4: Perform the request and get the response and assert. - mockMvc.perform(request) - // MvcResult Result = mockMvc.perform(request) - // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) - .andExpect(status().isCreated()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.category").value("Electronics")) - .andExpect(jsonPath("$.rating").value(5)); - - test_logger.info("Ending test: " + getCurrentMethodName() + ". "); - } - - @DisplayName("Delete Review") - @Test - public void deleteReviewTest() throws Exception { - test_logger.info("Starting test: " + getCurrentMethodName() + ". "); - - // Step 1: Create a Review object. - Review newReview = Review.builder().category("Electronics") - .reviewContent("Great smartphone with excellent features. ").rating(5).customerId(1) - .productId(2).build(); - - // Step 2: Convert the Java object to JSON using ObjectMapper. - String newReviewAsJSON = objectMapper.writeValueAsString(newReview); - - // Step 3: Build the request. - RequestBuilder request = MockMvcRequestBuilders.post("/reviews") - .contentType(MediaType.APPLICATION_JSON) - .content(newReviewAsJSON); - - // Step 4: Perform the request and get the response and assert. - mockMvc.perform(request) - // MvcResult Result = mockMvc.perform(request) - // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) - .andExpect(status().isCreated()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.category").value("Electronics")) - .andExpect(jsonPath("$.rating").value(5)); - - test_logger.info("Ending test: " + getCurrentMethodName() + ". "); - } + // @DisplayName("Get All Reviews") + // @Test + // public void getAllReviewsTest() throws Exception { + // test_logger.info("Starting test: " + getCurrentMethodName() + ". "); + + // // Step 1: Create a Review objects. + // Review newReview = Review.builder().category("Electronics") + // .reviewContent("Great smartphone with excellent features. ").rating(5).customerId(1) + // .productId(2).build(); + + // // Step 2: Convert the Java object to JSON using ObjectMapper. + // String newReviewAsJSON = objectMapper.writeValueAsString(newReview); + + // // Step 3: Build the request. + // RequestBuilder request = MockMvcRequestBuilders.post("/reviews") + // .contentType(MediaType.APPLICATION_JSON) + // .content(newReviewAsJSON); + + // // Step 4: Perform the request and get the response and assert. + // mockMvc.perform(request) + // // MvcResult Result = mockMvc.perform(request) + // // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) + // .andExpect(status().isCreated()) + // .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + // .andExpect(jsonPath("$.category").value("Electronics")) + // .andExpect(jsonPath("$.rating").value(5)); + + // test_logger.info("Ending test: " + getCurrentMethodName() + ". "); + // } + + // @DisplayName("Get One Review") + // @Test + // public void getOneReviewTest() throws Exception { + // test_logger.info("Starting test: " + getCurrentMethodName() + ". "); + + // // Step 1: Create a Review object. + // Review newReview = Review.builder().category("Electronics") + // .reviewContent("Great smartphone with excellent features. ").rating(5).customerId(1) + // .productId(2).build(); + + // // Step 2: Convert the Java object to JSON using ObjectMapper. + // String newReviewAsJSON = objectMapper.writeValueAsString(newReview); + + // // Step 3: Build the request. + // RequestBuilder request = MockMvcRequestBuilders.post("/reviews") + // .contentType(MediaType.APPLICATION_JSON) + // .content(newReviewAsJSON); + + // // Step 4: Perform the request and get the response and assert. + // mockMvc.perform(request) + // // MvcResult Result = mockMvc.perform(request) + // // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) + // .andExpect(status().isCreated()) + // .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + // .andExpect(jsonPath("$.category").value("Electronics")) + // .andExpect(jsonPath("$.rating").value(5)); + + // test_logger.info("Ending test: " + getCurrentMethodName() + ". "); + // } + + // @DisplayName("Update Review") + // @Test + // public void updateReviewTest() throws Exception { + // test_logger.info("Starting test: " + getCurrentMethodName() + ". "); + + // // Step 1: Create a Review object. + // Review newReview = Review.builder().category("Electronics") + // .reviewContent("Great smartphone with excellent features. ").rating(5).customerId(1) + // .productId(2).build(); + + // // Step 2: Convert the Java object to JSON using ObjectMapper. + // String newReviewAsJSON = objectMapper.writeValueAsString(newReview); + + // // Step 3: Build the request. + // RequestBuilder request = MockMvcRequestBuilders.post("/reviews") + // .contentType(MediaType.APPLICATION_JSON) + // .content(newReviewAsJSON); + + // // Step 4: Perform the request and get the response and assert. + // mockMvc.perform(request) + // // MvcResult Result = mockMvc.perform(request) + // // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) + // .andExpect(status().isCreated()) + // .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + // .andExpect(jsonPath("$.category").value("Electronics")) + // .andExpect(jsonPath("$.rating").value(5)); + + // test_logger.info("Ending test: " + getCurrentMethodName() + ". "); + // } + + // @DisplayName("Delete Review") + // @Test + // public void deleteReviewTest() throws Exception { + // test_logger.info("Starting test: " + getCurrentMethodName() + ". "); + + // // Step 1: Create a Review object. + // Review newReview = Review.builder().category("Electronics") + // .reviewContent("Great smartphone with excellent features. ").rating(5).customerId(1) + // .productId(2).build(); + + // // Step 2: Convert the Java object to JSON using ObjectMapper. + // String newReviewAsJSON = objectMapper.writeValueAsString(newReview); + + // // Step 3: Build the request. + // RequestBuilder request = MockMvcRequestBuilders.post("/reviews") + // .contentType(MediaType.APPLICATION_JSON) + // .content(newReviewAsJSON); + + // // Step 4: Perform the request and get the response and assert. + // mockMvc.perform(request) + // // MvcResult Result = mockMvc.perform(request) + // // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) + // .andExpect(status().isCreated()) + // .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + // .andExpect(jsonPath("$.category").value("Electronics")) + // .andExpect(jsonPath("$.rating").value(5)); + + // test_logger.info("Ending test: " + getCurrentMethodName() + ". "); + // } // >>>>>>> main } From cf05b1c05c141aed04fede1bb9b6259f4da00242 Mon Sep 17 00:00:00 2001 From: Izzat Fadzlon <52589461+kiblykat@users.noreply.github.com> Date: Tue, 26 Mar 2024 00:09:09 +0800 Subject: [PATCH 6/6] Update ReviewControllerTest.java --- .../controllers/ReviewControllerTest.java | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java b/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java index eefa75a..4d13242 100644 --- a/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java +++ b/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java @@ -84,34 +84,34 @@ public void getReviewTest() throws Exception { // Build the GET request RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/reviews/2"); //======= // = = = DATA INTEGRITY VIOLATION EXCEPTION = = = - public void createReviewTest() throws Exception { - test_logger.info("Starting test: " + getCurrentMethodName() + ". "); - - // Step 1: Create a Review object. - Review newReview = Review.builder().category("Electronics") - .reviewContent("Great smartphone with excellent features. ").rating(5).customerId(1) - .productId(2).build(); - - // Step 2: Convert the Java object to JSON using ObjectMapper. - String newReviewAsJSON = objectMapper.writeValueAsString(newReview); - - // Step 3: Build the request. - RequestBuilder request = MockMvcRequestBuilders.post("/reviews") - .contentType(MediaType.APPLICATION_JSON) - .content(newReviewAsJSON); - - // Step 4: Perform the request and get the response and assert. - mockMvc.perform(request) - // MvcResult Result = mockMvc.perform(request) - // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) - .andExpect(status().isCreated()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.category").value("Electronics")) - .andExpect(jsonPath("$.rating").value(5)); - // .andDo(print -> test_logger.error("Customer's id: {}", - // print.getResponse().getContentAsString())) - // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) - // .andReturn(); + // public void createReviewTest() throws Exception { + // test_logger.info("Starting test: " + getCurrentMethodName() + ". "); + + // // Step 1: Create a Review object. + // Review newReview = Review.builder().category("Electronics") + // .reviewContent("Great smartphone with excellent features. ").rating(5).customerId(1) + // .productId(2).build(); + + // // Step 2: Convert the Java object to JSON using ObjectMapper. + // String newReviewAsJSON = objectMapper.writeValueAsString(newReview); + + // // Step 3: Build the request. + // RequestBuilder request = MockMvcRequestBuilders.post("/reviews") + // .contentType(MediaType.APPLICATION_JSON) + // .content(newReviewAsJSON); + + // // Step 4: Perform the request and get the response and assert. + // mockMvc.perform(request) + // // MvcResult Result = mockMvc.perform(request) + // // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) + // .andExpect(status().isCreated()) + // .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + // .andExpect(jsonPath("$.category").value("Electronics")) + // .andExpect(jsonPath("$.rating").value(5)); + // // .andDo(print -> test_logger.error("Customer's id: {}", + // // print.getResponse().getContentAsString())) + // // .andDo(print -> test_logger.error("Starting Request: createReviewTest. ")) + // // .andReturn(); // >>>>>>> main // when(reviewService.getReview(2L)).thenReturn(testReview);