diff --git a/src/main/java/sg/com/smartinventory/utility/Utility.java b/src/main/java/sg/com/smartinventory/utility/Utility.java
new file mode 100644
index 0000000..bf168a5
--- /dev/null
+++ b/src/main/java/sg/com/smartinventory/utility/Utility.java
@@ -0,0 +1,105 @@
+package sg.com.smartinventory.utility;
+
+public class Utility {
+ /**
+ * Get the method name of the caller.
+ *
+ * Java 9 introduced the Stack-Walking API to traverse the JVM stack frames in a
+ * lazy and efficient manner.
+ * First, we get a StackWalker instance using the getInstance() factory method.
+ * Then we use the walk() method to traverse the stack frames from the top to
+ * the bottom:
+ *
+ *
+ * - The walk() method can convert a stream of stack frames —
+ * Stream — to anything.
+ *
- The first element in the given stream is the top frame on the stack.
+ *
- The top frame on the stack always represents the currently executing
+ * method.
+ *
+ *
+ * Therefore, if we get the first element from the stream, we’ll know the
+ * currently executing method details. More specifically, we can use
+ * StackFrame.getMethodName() to find the method name.
+ *
+ * Compared to other approaches (more on them later), the Stack-Walking API has
+ * a few advantages:
+ *
+ *
+ *
+ * No need to create a dummy anonymous inner class instance — new
+ * Object().getClass() {}
+ *
+ * No need to create a dummy exception — new Throwable()
+ *
+ * No need to eagerly capture the whole stacktrace, which can be costly
+ *
+ *
+ * On the contrary, the StackWalker only walks the stack one by one in a lazy
+ * fashion. In this case, it only fetches the top frame, as opposed to the
+ * stacktrace approach which captures all the frames eagerly.
+ *
+ * @param levelsUp The number of levels up the stack trace.
+ *
+ * @return The method name of the caller.
+ */
+ public static String getMethodName(int levelsUp) {
+ // Check if the levelsUp is less than 0. If it is, throw an exception.
+ if (levelsUp < 0) {
+ throw new IllegalArgumentException("levelsUp must be greater than or equal to 0. ");
+ }
+
+ // Get the method name of the caller. The top is this function name itself, so
+ // it should be skipped.
+ return StackWalker.getInstance()
+ .walk(s -> s.skip(1 + levelsUp).findFirst())
+ .get()
+ .getMethodName();
+ }
+
+ /**
+ * Get the current method name.
+ *
+ * @return The current method name.
+ *
+ * @see #getMethodName()
+ */
+ public static String getCurrentMethodName() {
+ // Get the method name of the caller. You need to skip 1 level up to get the
+ // current method name as you are calling a base function below it.
+ return getMethodName(1);
+ }
+
+ /**
+ * Get the caller method name.
+ *
+ * @return The caller method name.
+ *
+ * @see #getMethodName()
+ */
+ public static String getCallerMethodName() {
+ // Get the method name of the caller. You need to skip 2 level up to get the
+ // current method name as you are calling a base function below it.
+ return getMethodName(2);
+ }
+
+ /**
+ * Get the caller method name.
+ *
+ * @param levelsUp The number of levels up the stack trace.
+ *
+ * @return The caller method name.
+ *
+ * @see #getCallerMethodName()
+ */
+ public static String getCallerMethodName(int levelsUp) {
+ // Check if the levelsUp is less than 0. If it is, throw an exception.
+ if (levelsUp < 0) {
+ throw new IllegalArgumentException("levelsUp must be greater than or equal to 0. ");
+ }
+
+ // Get the method name of the caller. You need to skip 1 level up to get the
+ // current method name as you are calling a base function below it.
+ return getMethodName(2 + levelsUp);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/SmartInventoryApplicationTests.java b/src/test/java/sg/com/smartinventory/SmartInventoryApplicationTests.java
index fdac9f6..3558490 100644
--- a/src/test/java/sg/com/smartinventory/SmartInventoryApplicationTests.java
+++ b/src/test/java/sg/com/smartinventory/SmartInventoryApplicationTests.java
@@ -1,13 +1,28 @@
package sg.com.smartinventory;
+import static sg.com.smartinventory.utility.Utility.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SmartInventoryApplicationTests {
+ /// Name this according to your class name.
+ // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
+ // INFO, WARN, ERROR, with each of these having a corresponding logging method:
+ // trace(), debug(), info(), warn(), error().
+ private static final Logger test_logger = LoggerFactory.getLogger(SmartInventoryApplicationTests.class);
+
@Test
void contextLoads() {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/controllers/CustomerControllerTest.java b/src/test/java/sg/com/smartinventory/controllers/CustomerControllerTest.java
index a3ab485..ac43068 100644
--- a/src/test/java/sg/com/smartinventory/controllers/CustomerControllerTest.java
+++ b/src/test/java/sg/com/smartinventory/controllers/CustomerControllerTest.java
@@ -1,7 +1,13 @@
package sg.com.smartinventory.controllers;
+import static sg.com.smartinventory.utility.Utility.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
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;
@@ -35,10 +41,21 @@ public class CustomerControllerTest {
// trace(), debug(), info(), warn(), error().
private static final Logger test_logger = LoggerFactory.getLogger(CustomerControllerTest.class);
- @DisplayName("Create customer")
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
+ }
+
+ @DisplayName("Create Customer")
@Test
public void createCustomerTest() throws Exception {
- test_logger.info("Starting test: createCustomerTest. ");
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
// Step 1: Create a Customer object
Customer newCustomer = Customer.builder().firstName("Jackie").lastName("Chan").country("Hong Kong")
@@ -60,6 +77,6 @@ public void createCustomerTest() throws Exception {
.andExpect(jsonPath("$.firstName").value("Jackie"))
.andExpect(jsonPath("$.lastName").value("Chan"));
- test_logger.info("Ending test: createCustomerTest. ");
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/controllers/ProductControllerTest.java b/src/test/java/sg/com/smartinventory/controllers/ProductControllerTest.java
index b2955f4..2d38633 100644
--- a/src/test/java/sg/com/smartinventory/controllers/ProductControllerTest.java
+++ b/src/test/java/sg/com/smartinventory/controllers/ProductControllerTest.java
@@ -1,7 +1,13 @@
package sg.com.smartinventory.controllers;
+import static sg.com.smartinventory.utility.Utility.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
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;
@@ -33,12 +39,23 @@ public class ProductControllerTest {
// The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
// INFO, WARN, ERROR, with each of these having a corresponding logging method:
// trace(), debug(), info(), warn(), error().
- private static final Logger test_logger = LoggerFactory.getLogger(CustomerControllerTest.class);
+ private static final Logger test_logger = LoggerFactory.getLogger(ProductControllerTest.class);
+
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
+ }
- @DisplayName("Create product")
+ @DisplayName("Create Product")
@Test
public void createProductTest() throws Exception {
- test_logger.info("Starting test: createProductTest. ");
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
// Step 1: Create a Product object
Product newProduct = Product.builder().category("Electronics").name("Smartphone")
@@ -60,6 +77,6 @@ public void createProductTest() throws Exception {
.andExpect(jsonPath("$.category").value("Electronics"))
.andExpect(jsonPath("$.name").value("Smartphone"));
- test_logger.info("Ending test: createProductTest. ");
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ 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 d7c0cde..92c140f 100644
--- a/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java
+++ b/src/test/java/sg/com/smartinventory/controllers/ReviewControllerTest.java
@@ -1,7 +1,13 @@
package sg.com.smartinventory.controllers;
+import static sg.com.smartinventory.utility.Utility.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
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;
@@ -13,7 +19,6 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@@ -30,39 +35,32 @@ public class ReviewControllerTest {
@Autowired
private ObjectMapper objectMapper;
- /**
- * Convert JSON Result to object.
- *
- * @param result The contents.
- * @param tClass The expected object class.
- * @return The result as a class object.
- * @throws Exception
- */
- public T fromJsonResult(MvcResult result, Class tClass) throws Exception {
- return this.objectMapper.readValue(result.getResponse().getContentAsString(), tClass);
+ /// Name this according to your class name.
+ // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
+ // INFO, WARN, ERROR, with each of these having a corresponding logging method:
+ // trace(), debug(), info(), warn(), error().
+ private static final Logger test_logger = LoggerFactory.getLogger(ReviewControllerTest.class);
+
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
}
/**
- * Convert object to JSON bytes.
+ * Test the creation of a Review.
*
- * @param object The object to JSON-ify.
- * @return Byte array with JSON representation.
* @throws Exception
*/
- public byte[] toJson(Object object) throws Exception {
- return this.objectMapper.writeValueAsString(object).getBytes();
- }
-
- /// Name this according to your class name.
- // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
- // INFO, WARN, ERROR, with each of these having a corresponding logging method:
- // trace(), debug(), info(), warn(), error().
- private static final Logger test_logger = LoggerFactory.getLogger(CustomerControllerTest.class);
-
- @DisplayName("Create review")
+ @DisplayName("Create Review")
@Test
public void createReviewTest() throws Exception {
- test_logger.info("Starting test: createReviewTest. ");
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
// Step 1: Create a Review object
Review newReview = Review.builder().category("Electronics")
@@ -93,6 +91,6 @@ public void createReviewTest() throws Exception {
// Review ReviewObject = fromJsonResult(Result, Review.class);
// test_logger.error("Ending test: createReviewTest. ");
- test_logger.info("Ending test: createReviewTest. ");
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/sg/com/smartinventory/entities/CustomerTest.java b/src/test/java/sg/com/smartinventory/entities/CustomerTest.java
index 350c448..b8d16f2 100644
--- a/src/test/java/sg/com/smartinventory/entities/CustomerTest.java
+++ b/src/test/java/sg/com/smartinventory/entities/CustomerTest.java
@@ -1,11 +1,20 @@
package sg.com.smartinventory.entities;
+import static sg.com.smartinventory.utility.Utility.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+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;
+
import sg.com.smartinventory.repositories.CustomerRepository;
import sg.com.smartinventory.serviceImpls.CustomerServiceImpl;
@@ -16,9 +25,28 @@ public class CustomerTest {
@InjectMocks
CustomerServiceImpl customerService;
+ /// Name this according to your class name.
+ // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
+ // INFO, WARN, ERROR, with each of these having a corresponding logging method:
+ // trace(), debug(), info(), warn(), error().
+ private static final Logger test_logger = LoggerFactory.getLogger(CustomerTest.class);
+
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
+ }
+
@DisplayName("Customer Test")
@Test
public void customerTest() throws Exception {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/entities/ErrorResponseTest.java b/src/test/java/sg/com/smartinventory/entities/ErrorResponseTest.java
index ae73c98..e77bd62 100644
--- a/src/test/java/sg/com/smartinventory/entities/ErrorResponseTest.java
+++ b/src/test/java/sg/com/smartinventory/entities/ErrorResponseTest.java
@@ -1,15 +1,43 @@
package sg.com.smartinventory.entities;
+import static sg.com.smartinventory.utility.Utility.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+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;
+
public class ErrorResponseTest {
+ /// Name this according to your class name.
+ // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
+ // INFO, WARN, ERROR, with each of these having a corresponding logging method:
+ // trace(), debug(), info(), warn(), error().
+ private static final Logger test_logger = LoggerFactory.getLogger(ErrorResponseTest.class);
+
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
+ }
+
@DisplayName("Error Response Test")
@Test
public void errorResponseTest() throws Exception {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/entities/ProductTest.java b/src/test/java/sg/com/smartinventory/entities/ProductTest.java
index 0dcbce6..1ec09a1 100644
--- a/src/test/java/sg/com/smartinventory/entities/ProductTest.java
+++ b/src/test/java/sg/com/smartinventory/entities/ProductTest.java
@@ -1,11 +1,20 @@
package sg.com.smartinventory.entities;
+import static sg.com.smartinventory.utility.Utility.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+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;
+
import sg.com.smartinventory.repositories.ProductRepository;
// import sg.com.smartinventory.serviceImpls.ProductServiceImpl;
@@ -16,9 +25,28 @@ public class ProductTest {
// @InjectMocks
// ProductServiceImpl productService;
+ /// Name this according to your class name.
+ // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
+ // INFO, WARN, ERROR, with each of these having a corresponding logging method:
+ // trace(), debug(), info(), warn(), error().
+ private static final Logger test_logger = LoggerFactory.getLogger(ProductTest.class);
+
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
+ }
+
@DisplayName("Product Test")
@Test
public void productTest() throws Exception {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/entities/ReviewTest.java b/src/test/java/sg/com/smartinventory/entities/ReviewTest.java
index b24d7ec..43479ff 100644
--- a/src/test/java/sg/com/smartinventory/entities/ReviewTest.java
+++ b/src/test/java/sg/com/smartinventory/entities/ReviewTest.java
@@ -1,11 +1,20 @@
package sg.com.smartinventory.entities;
+import static sg.com.smartinventory.utility.Utility.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+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;
+
import sg.com.smartinventory.repositories.ReviewRepository;
// import sg.com.smartinventory.serviceImpls.ReviewServiceImpl;
@@ -16,9 +25,28 @@ public class ReviewTest {
// @InjectMocks
// ReviewServiceImpl reviewService;
+ /// Name this according to your class name.
+ // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
+ // INFO, WARN, ERROR, with each of these having a corresponding logging method:
+ // trace(), debug(), info(), warn(), error().
+ private static final Logger test_logger = LoggerFactory.getLogger(ReviewTest.class);
+
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
+ }
+
@DisplayName("Review Test")
@Test
public void reviewTest() throws Exception {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/integration/IntegrationTest.java b/src/test/java/sg/com/smartinventory/integration/IntegrationTest.java
index 459c31b..8e9f383 100644
--- a/src/test/java/sg/com/smartinventory/integration/IntegrationTest.java
+++ b/src/test/java/sg/com/smartinventory/integration/IntegrationTest.java
@@ -1,6 +1,8 @@
package sg.com.smartinventory.integration;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static sg.com.smartinventory.utility.Utility.*;
+
+import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -8,12 +10,17 @@
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;
+
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
@@ -43,9 +50,28 @@ public class IntegrationTest {
@Autowired
private ObjectMapper objectMapper;
+ /// Name this according to your class name.
+ // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
+ // INFO, WARN, ERROR, with each of these having a corresponding logging method:
+ // trace(), debug(), info(), warn(), error().
+ private static final Logger test_logger = LoggerFactory.getLogger(IntegrationTest.class);
+
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
+ }
+
@DisplayName("Integration Test 1")
@Test
public void createCustomerTest() {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
+
// 1. Setup.
Customer testObject1 = Customer.builder().firstName("Jackie").lastName("Chan").country("Hong Kong")
.address("123 HK St").postalCode(654321).phoneNumber(87654321)
@@ -62,11 +88,15 @@ public void createCustomerTest() {
// Verify that the save method of the customer repository is called once.
verify(customerRepository, times(1)).save(testObject1);
+
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
@DisplayName("Integration Test 2")
@Test
public void runIntegratedTest() throws Exception {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
+
// Step 1: Create the test objects.
Customer testObject1 = Customer.builder().firstName("Jackie").lastName("Chan").country("Hong Kong")
.address("123 HK St").postalCode(654321).phoneNumber(87654321)
@@ -98,5 +128,7 @@ public void runIntegratedTest() throws Exception {
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.firstName").value("Jackie"))
.andExpect(jsonPath("$.lastName").value("Chang"));
+
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/services/CustomerServiceImplTest.java b/src/test/java/sg/com/smartinventory/services/CustomerServiceImplTest.java
index ebc57ea..e60a73c 100644
--- a/src/test/java/sg/com/smartinventory/services/CustomerServiceImplTest.java
+++ b/src/test/java/sg/com/smartinventory/services/CustomerServiceImplTest.java
@@ -1,16 +1,23 @@
package sg.com.smartinventory.services;
+import static sg.com.smartinventory.utility.Utility.*;
+
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import org.springframework.boot.test.context.SpringBootTest;
import sg.com.smartinventory.entities.Customer;
@@ -25,8 +32,26 @@ public class CustomerServiceImplTest {
@InjectMocks
CustomerServiceImpl customerService;
+ /// Name this according to your class name.
+ // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
+ // INFO, WARN, ERROR, with each of these having a corresponding logging method:
+ // trace(), debug(), info(), warn(), error().
+ private static final Logger test_logger = LoggerFactory.getLogger(CustomerServiceImplTest.class);
+
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
+ }
+
@Test
public void createCustomerTest() {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
// 1. SETUP
// Create a new customer.
@@ -44,5 +69,7 @@ public void createCustomerTest() {
// Verify that the save method of the customer repository is called once only.
verify(customerRepository, times(1)).save(customer);
+
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/services/ProductServiceImplTest.java b/src/test/java/sg/com/smartinventory/services/ProductServiceImplTest.java
index 516e6c1..9f2b3e7 100644
--- a/src/test/java/sg/com/smartinventory/services/ProductServiceImplTest.java
+++ b/src/test/java/sg/com/smartinventory/services/ProductServiceImplTest.java
@@ -1,16 +1,23 @@
package sg.com.smartinventory.services;
+import static sg.com.smartinventory.utility.Utility.*;
+
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import org.springframework.boot.test.context.SpringBootTest;
import sg.com.smartinventory.entities.Product;
@@ -25,8 +32,26 @@ public class ProductServiceImplTest {
@InjectMocks
ProductServiceImpl productService;
+ /// Name this according to your class name.
+ // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
+ // INFO, WARN, ERROR, with each of these having a corresponding logging method:
+ // trace(), debug(), info(), warn(), error().
+ private static final Logger test_logger = LoggerFactory.getLogger(ProductServiceImplTest.class);
+
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
+ }
+
@Test
public void createProductTest() {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
// 1. SETUP
// Create a new product.
@@ -45,5 +70,7 @@ public void createProductTest() {
// Verify that the save method of the product repository is called once only.
verify(productRepository, times(1)).save(product);
+
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/services/ReviewServiceImplTest.java b/src/test/java/sg/com/smartinventory/services/ReviewServiceImplTest.java
index a13ebd9..6d85aac 100644
--- a/src/test/java/sg/com/smartinventory/services/ReviewServiceImplTest.java
+++ b/src/test/java/sg/com/smartinventory/services/ReviewServiceImplTest.java
@@ -1,16 +1,23 @@
package sg.com.smartinventory.services;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static sg.com.smartinventory.utility.Utility.*;
+
+import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import org.springframework.boot.test.context.SpringBootTest;
import sg.com.smartinventory.entities.Review;
@@ -25,8 +32,26 @@ public class ReviewServiceImplTest {
@InjectMocks
ReviewServiceImpl reviewService;
+ /// Name this according to your class name.
+ // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
+ // INFO, WARN, ERROR, with each of these having a corresponding logging method:
+ // trace(), debug(), info(), warn(), error().
+ private static final Logger test_logger = LoggerFactory.getLogger(ReviewServiceImplTest.class);
+
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
+ }
+
@Test
public void createReviewTest() {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
// 1. SETUP
// Create a new review.
@@ -45,5 +70,7 @@ public void createReviewTest() {
// Verify that the save method of the review repository is called once only.
verify(reviewRepository, times(1)).save(review);
+
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/useCases/UseCaseTest.java b/src/test/java/sg/com/smartinventory/useCases/UseCaseTest.java
index 3190eb4..12c80a0 100644
--- a/src/test/java/sg/com/smartinventory/useCases/UseCaseTest.java
+++ b/src/test/java/sg/com/smartinventory/useCases/UseCaseTest.java
@@ -1,6 +1,8 @@
package sg.com.smartinventory.useCases;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static sg.com.smartinventory.utility.Utility.*;
+
+import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -8,12 +10,17 @@
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;
+
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
@@ -43,9 +50,28 @@ public class UseCaseTest {
@Autowired
private ObjectMapper objectMapper;
+ /// Name this according to your class name.
+ // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
+ // INFO, WARN, ERROR, with each of these having a corresponding logging method:
+ // trace(), debug(), info(), warn(), error().
+ private static final Logger test_logger = LoggerFactory.getLogger(UseCaseTest.class);
+
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
+ }
+
@DisplayName("Use Case Test 1")
@Test
public void createCustomerTest() {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
+
// 1. Setup.
Customer testObject1 = Customer.builder().firstName("Jackie").lastName("Chan").country("Hong Kong")
.address("123 HK St").postalCode(654321).phoneNumber(87654321)
@@ -62,11 +88,15 @@ public void createCustomerTest() {
// Verify that the save method of the customer repository is called once.
verify(customerRepository, times(1)).save(testObject1);
+
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
@DisplayName("Use Case Test 2")
@Test
public void runIntegratedTest() throws Exception {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
+
// Step 1: Create the test objects.
Customer testObject1 = Customer.builder().firstName("Jackie").lastName("Chan").country("Hong Kong")
.address("123 HK St").postalCode(654321).phoneNumber(87654321)
@@ -98,5 +128,7 @@ public void runIntegratedTest() throws Exception {
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.firstName").value("Jackie"))
.andExpect(jsonPath("$.lastName").value("Chang"));
+
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/utility/DataLoaderTest.java b/src/test/java/sg/com/smartinventory/utility/DataLoaderTest.java
index 1def923..36fb8e6 100644
--- a/src/test/java/sg/com/smartinventory/utility/DataLoaderTest.java
+++ b/src/test/java/sg/com/smartinventory/utility/DataLoaderTest.java
@@ -1,11 +1,20 @@
package sg.com.smartinventory.utility;
+import static sg.com.smartinventory.utility.Utility.*;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+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;
+
import sg.com.smartinventory.repositories.CustomerRepository;
// import sg.com.smartinventory.serviceImpls.CustomerServiceImpl;
import sg.com.smartinventory.repositories.ProductRepository;
@@ -24,9 +33,28 @@ public class DataLoaderTest {
// ProductServiceImpl productService;
// ReviewServiceImpl reviewService;
+ /// Name this according to your class name.
+ // The Logback library defines 5 log levels in order of priority: TRACE, DEBUG,
+ // INFO, WARN, ERROR, with each of these having a corresponding logging method:
+ // trace(), debug(), info(), warn(), error().
+ private static final Logger test_logger = LoggerFactory.getLogger(DataLoaderTest.class);
+
+ // Test Setup and Teardown configuration.
+ @BeforeEach
+ void init() {
+
+ }
+
+ @AfterEach
+ void teardown() {
+
+ }
+
@DisplayName("DataLoader Test")
@Test
public void dataLoaderTest() throws Exception {
+ test_logger.info("Starting test: " + getCurrentMethodName() + ". ");
+ test_logger.info("Ending test: " + getCurrentMethodName() + ". ");
}
}
\ No newline at end of file
diff --git a/src/test/java/sg/com/smartinventory/utility/Utility.java b/src/test/java/sg/com/smartinventory/utility/Utility.java
new file mode 100644
index 0000000..b96e1b6
--- /dev/null
+++ b/src/test/java/sg/com/smartinventory/utility/Utility.java
@@ -0,0 +1,138 @@
+package sg.com.smartinventory.utility;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.web.servlet.MvcResult;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class Utility {
+ @Autowired
+ private static ObjectMapper objectMapper;
+
+ /**
+ * Get the method name of the caller.
+ *
+ * Java 9 introduced the Stack-Walking API to traverse the JVM stack frames in a
+ * lazy and efficient manner.
+ * First, we get a StackWalker instance using the getInstance() factory method.
+ * Then we use the walk() method to traverse the stack frames from the top to
+ * the bottom:
+ *
+ *
+ * - The walk() method can convert a stream of stack frames —
+ * Stream — to anything.
+ *
- The first element in the given stream is the top frame on the stack.
+ *
- The top frame on the stack always represents the currently executing
+ * method.
+ *
+ *
+ * Therefore, if we get the first element from the stream, we’ll know the
+ * currently executing method details. More specifically, we can use
+ * StackFrame.getMethodName() to find the method name.
+ *
+ * Compared to other approaches (more on them later), the Stack-Walking API has
+ * a few advantages:
+ *
+ *
+ *
+ * No need to create a dummy anonymous inner class instance — new
+ * Object().getClass() {}
+ *
+ * No need to create a dummy exception — new Throwable()
+ *
+ * No need to eagerly capture the whole stacktrace, which can be costly
+ *
+ *
+ * On the contrary, the StackWalker only walks the stack one by one in a lazy
+ * fashion. In this case, it only fetches the top frame, as opposed to the
+ * stacktrace approach which captures all the frames eagerly.
+ *
+ * @param levelsUp The number of levels up the stack trace.
+ *
+ * @return The method name of the caller.
+ */
+ public static String getMethodName(int levelsUp) {
+ // Check if the levelsUp is less than 0. If it is, throw an exception.
+ if (levelsUp < 0) {
+ throw new IllegalArgumentException("levelsUp must be greater than or equal to 0. ");
+ }
+
+ // Get the method name of the caller. The top is this function name itself, so
+ // it should be skipped.
+ return StackWalker.getInstance()
+ .walk(s -> s.skip(1 + levelsUp).findFirst())
+ .get()
+ .getMethodName();
+ }
+
+ /**
+ * Get the current method name.
+ *
+ * @return The current method name.
+ *
+ * @see #getMethodName()
+ */
+ public static String getCurrentMethodName() {
+ // Get the method name of the caller. You need to skip 1 level up to get the
+ // current method name as you are calling a base function below it.
+ return getMethodName(1);
+ }
+
+ /**
+ * Get the caller method name.
+ *
+ * @return The caller method name.
+ *
+ * @see #getMethodName()
+ */
+ public static String getCallerMethodName() {
+ // Get the method name of the caller. You need to skip 2 level up to get the
+ // current method name as you are calling a base function below it.
+ return getMethodName(2);
+ }
+
+ /**
+ * Get the caller method name.
+ *
+ * @param levelsUp The number of levels up the stack trace.
+ *
+ * @return The caller method name.
+ *
+ * @see #getCallerMethodName()
+ */
+ public static String getCallerMethodName(int levelsUp) {
+ // Check if the levelsUp is less than 0. If it is, throw an exception.
+ if (levelsUp < 0) {
+ throw new IllegalArgumentException("levelsUp must be greater than or equal to 0. ");
+ }
+
+ // Get the method name of the caller. You need to skip 1 level up to get the
+ // current method name as you are calling a base function below it.
+ return getMethodName(2 + levelsUp);
+ }
+
+ /**
+ * Convert JSON Result to object.
+ *
+ * @param result The contents.
+ * @param tClass The expected object class.
+ *
+ * @return The result as a class object.
+ * @throws Exception
+ */
+ public static T fromJsonResult(MvcResult result, Class tClass) throws Exception {
+ return objectMapper.readValue(result.getResponse().getContentAsString(), tClass);
+ }
+
+ /**
+ * Convert object to JSON bytes.
+ *
+ * @param object The object to JSON-ify.
+ *
+ * @return Byte array with JSON representation.
+ * @throws Exception
+ */
+ public static byte[] toJson(Object object) throws Exception {
+ return objectMapper.writeValueAsString(object).getBytes();
+ }
+}
\ No newline at end of file