From d4d5094e1b97ce543ba6288ed2a4b7cce5c8a750 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Fri, 3 Apr 2026 20:22:41 +0200 Subject: [PATCH 1/6] Add unit tests for `CommentEntity` - Introduced comprehensive unit tests for `Comment` entity covering: - Getters and setters for all fields. - Lifecycle methods (`onCreate` and `onUpdate`). - Null-value validations prior to persistence. --- .../vet1177/entities/CommentEntityTest.java | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/test/java/org/example/vet1177/entities/CommentEntityTest.java diff --git a/src/test/java/org/example/vet1177/entities/CommentEntityTest.java b/src/test/java/org/example/vet1177/entities/CommentEntityTest.java new file mode 100644 index 00000000..8e39dd5d --- /dev/null +++ b/src/test/java/org/example/vet1177/entities/CommentEntityTest.java @@ -0,0 +1,117 @@ +package org.example.vet1177.entities; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.time.Instant; + +import static org.assertj.core.api.Assertions.assertThat; + +class CommentEntityTest { + + private Comment comment; + private User author; + private MedicalRecord medicalRecord; + + @BeforeEach + void setUp() { + comment = new Comment(); + author = new User("Dr. Elin Svensson", "elin@vet.se", "hash123", Role.VET); + medicalRecord = new MedicalRecord(); + } + + // --- Getters & setters --- + + @Test + void setBody_shouldStoreAndReturnCorrectValue() { + comment.setBody("Patienten visar tecken på förbättring."); + + assertThat(comment.getBody()).isEqualTo("Patienten visar tecken på förbättring."); + } + + @Test + void setAuthor_shouldStoreAndReturnCorrectUser() { + comment.setAuthor(author); + + assertThat(comment.getAuthor()).isSameAs(author); + } + + @Test + void setMedicalRecord_shouldStoreAndReturnCorrectRecord() { + comment.setMedicalRecord(medicalRecord); + + assertThat(comment.getMedicalRecord()).isSameAs(medicalRecord); + } + + // --- Lifecycle: onCreate --- + + @Test + void onCreate_shouldSetBothTimestampsToNonNull() { + comment.onCreate(); + + assertThat(comment.getCreatedAt()).isNotNull(); + assertThat(comment.getUpdatedAt()).isNotNull(); + } + + @Test + void onCreate_createdAtAndUpdatedAtShouldBeEqual() { + comment.onCreate(); + + assertThat(comment.getCreatedAt()).isEqualTo(comment.getUpdatedAt()); + } + + // --- Lifecycle: onUpdate --- + + @Test + void onUpdate_shouldRefreshUpdatedAtWithoutModifyingCreatedAt() { + comment.onCreate(); + Instant createdAt = comment.getCreatedAt(); + + comment.onUpdate(); + + assertThat(comment.getUpdatedAt()).isNotNull(); + assertThat(comment.getCreatedAt()).isEqualTo(createdAt); + } + + @Test + void onUpdate_shouldNotModifyCreatedAt() { + comment.onCreate(); + Instant originalCreatedAt = comment.getCreatedAt(); + + comment.onUpdate(); + + assertThat(comment.getCreatedAt()).isEqualTo(originalCreatedAt); + } + + // --- Sad paths: standardvärden innan persist --- + + @Test + void getId_shouldBeNullBeforePersist() { + assertThat(comment.getId()).isNull(); + } + + @Test + void getBody_shouldBeNullWhenNotSet() { + assertThat(comment.getBody()).isNull(); + } + + @Test + void getAuthor_shouldBeNullWhenNotSet() { + assertThat(comment.getAuthor()).isNull(); + } + + @Test + void getMedicalRecord_shouldBeNullWhenNotSet() { + assertThat(comment.getMedicalRecord()).isNull(); + } + + @Test + void getCreatedAt_shouldBeNullBeforeOnCreate() { + assertThat(comment.getCreatedAt()).isNull(); + } + + @Test + void getUpdatedAt_shouldBeNullBeforeOnCreate() { + assertThat(comment.getUpdatedAt()).isNull(); + } +} From a065eaa66c7af15aea455a914ac2b52660acbcc7 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Sat, 4 Apr 2026 11:54:07 +0200 Subject: [PATCH 2/6] Add unit tests for `CommentResponse` - Added comprehensive unit tests for `CommentResponse` covering: - Field mapping from `Comment` entity. - Validation of null cases for `author` and `medicalRecord`. - Timestamps (`createdAt`, `updatedAt`) consistency checks. --- .../response/comment/CommentResponseTest.java | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/test/java/org/example/vet1177/dto/response/comment/CommentResponseTest.java diff --git a/src/test/java/org/example/vet1177/dto/response/comment/CommentResponseTest.java b/src/test/java/org/example/vet1177/dto/response/comment/CommentResponseTest.java new file mode 100644 index 00000000..4c8fe81f --- /dev/null +++ b/src/test/java/org/example/vet1177/dto/response/comment/CommentResponseTest.java @@ -0,0 +1,108 @@ +package org.example.vet1177.dto.response.comment; + +import org.example.vet1177.entities.Comment; +import org.example.vet1177.entities.MedicalRecord; +import org.example.vet1177.entities.Role; +import org.example.vet1177.entities.User; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.time.Instant; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class CommentResponseTest { + + private Comment comment; + private User author; + private MedicalRecord medicalRecord; + private UUID commentId; + private UUID authorId; + private UUID recordId; + + @BeforeEach + void setUp() throws Exception { + commentId = UUID.randomUUID(); + authorId = UUID.randomUUID(); + recordId = UUID.randomUUID(); + + author = new User("Dr. Sara Lindqvist", "sara@vet.se", "hash", Role.VET); + setPrivateField(author, "id", authorId); + + medicalRecord = new MedicalRecord(); + medicalRecord.setId(recordId); + + comment = new Comment(); + setPrivateField(comment, "id", commentId); + comment.setBody("Djuret är friskt och kan skrivas ut."); + comment.setAuthor(author); + comment.setMedicalRecord(medicalRecord); + callProtectedMethod(comment, "onCreate"); + } + + // --- Happy path --- + + @Test + void from_shouldMapAllFieldsCorrectly() { + CommentResponse response = CommentResponse.from(comment); + + assertThat(response.id()).isEqualTo(commentId); + assertThat(response.recordId()).isEqualTo(recordId); + assertThat(response.authorId()).isEqualTo(authorId); + assertThat(response.authorName()).isEqualTo("Dr. Sara Lindqvist"); + assertThat(response.body()).isEqualTo("Djuret är friskt och kan skrivas ut."); + assertThat(response.createdAt()).isNotNull(); + assertThat(response.updatedAt()).isNotNull(); + } + + @Test + void from_createdAtAndUpdatedAtShouldReflectCommentTimestamps() { + CommentResponse response = CommentResponse.from(comment); + + assertThat(response.createdAt()).isEqualTo(comment.getCreatedAt()); + assertThat(response.updatedAt()).isEqualTo(comment.getUpdatedAt()); + } + + @Test + void from_shouldMapAuthorNameFromUserEntity() { + CommentResponse response = CommentResponse.from(comment); + + assertThat(response.authorName()).isEqualTo(author.getName()); + } + + // --- Sad paths --- + + @Test + void from_shouldThrowWhenAuthorIsNull() { + comment.setAuthor(null); + + assertThatThrownBy(() -> CommentResponse.from(comment)) + .isInstanceOf(NullPointerException.class); + } + + @Test + void from_shouldThrowWhenMedicalRecordIsNull() { + comment.setMedicalRecord(null); + + assertThatThrownBy(() -> CommentResponse.from(comment)) + .isInstanceOf(NullPointerException.class); + } + + // --- Helpers --- + + private static void setPrivateField(Object target, String fieldName, Object value) throws Exception { + Field field = target.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(target, value); + } + + private static void callProtectedMethod(Object target, String methodName) throws Exception { + Method method = target.getClass().getDeclaredMethod(methodName); + method.setAccessible(true); + method.invoke(target); + } +} From 4eac8c64b2d99840540597d3f80137a0ab749b1a Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Sat, 4 Apr 2026 12:26:47 +0200 Subject: [PATCH 3/6] Add JaCoCo plugin and remove redundant test method - Introduced JaCoCo Maven plugin for code coverage reporting. - Removed redundant `onCreate_createdAtAndUpdatedAtShouldBeEqual` test from `CommentEntityTest`. --- pom.xml | 34 +++++++++++++++++++ .../vet1177/entities/CommentEntityTest.java | 6 ---- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 083ac4b6..23354c8e 100644 --- a/pom.xml +++ b/pom.xml @@ -86,6 +86,8 @@ s3 2.20.0 + + @@ -94,7 +96,39 @@ org.springframework.boot spring-boot-maven-plugin + + org.jacoco + jacoco-maven-plugin + 0.8.14 + + + prepare-agent + + prepare-agent + + + + report + prepare-package + + report + + + + post-unit-test + test + + report + + + target/jacoco.exec + target/jacoco-ut + + + + + diff --git a/src/test/java/org/example/vet1177/entities/CommentEntityTest.java b/src/test/java/org/example/vet1177/entities/CommentEntityTest.java index 8e39dd5d..603f7ea8 100644 --- a/src/test/java/org/example/vet1177/entities/CommentEntityTest.java +++ b/src/test/java/org/example/vet1177/entities/CommentEntityTest.java @@ -53,12 +53,6 @@ void onCreate_shouldSetBothTimestampsToNonNull() { assertThat(comment.getUpdatedAt()).isNotNull(); } - @Test - void onCreate_createdAtAndUpdatedAtShouldBeEqual() { - comment.onCreate(); - - assertThat(comment.getCreatedAt()).isEqualTo(comment.getUpdatedAt()); - } // --- Lifecycle: onUpdate --- From 599e0d7cd79d9aacc597b7cf89c6b592e230a39e Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Sat, 4 Apr 2026 12:27:08 +0200 Subject: [PATCH 4/6] Add validation tests for `CreateCommentRequest` and `UpdateCommentRequest` - Introduced unit tests to validate fields and constraints in `CreateCommentRequest` and `UpdateCommentRequest`. - Covered both valid and invalid scenarios for request bodies and identifiers. --- .../CreateCommentRequestValidationTest.java | 108 ++++++++++++++++++ .../UpdateCommentRequestValidationTest.java | 86 ++++++++++++++ 2 files changed, 194 insertions(+) create mode 100644 src/test/java/org/example/vet1177/dto/request/comment/CreateCommentRequestValidationTest.java create mode 100644 src/test/java/org/example/vet1177/dto/request/comment/UpdateCommentRequestValidationTest.java diff --git a/src/test/java/org/example/vet1177/dto/request/comment/CreateCommentRequestValidationTest.java b/src/test/java/org/example/vet1177/dto/request/comment/CreateCommentRequestValidationTest.java new file mode 100644 index 00000000..c50b0d5f --- /dev/null +++ b/src/test/java/org/example/vet1177/dto/request/comment/CreateCommentRequestValidationTest.java @@ -0,0 +1,108 @@ +package org.example.vet1177.dto.request.comment; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Set; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +class CreateCommentRequestValidationTest { + + private Validator validator; + + @BeforeEach + void setUp() { + try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) { + validator = factory.getValidator(); + } + } + + // --- Happy paths --- + + @Test + void validRequest_shouldProduceNoViolations() { + var request = new CreateCommentRequest(UUID.randomUUID(), "En giltig kommentar."); + + Set> violations = validator.validate(request); + + assertThat(violations).isEmpty(); + } + + @Test + void bodyWithExactly5000Characters_shouldProduceNoViolations() { + var request = new CreateCommentRequest(UUID.randomUUID(), "x".repeat(5000)); + + Set> violations = validator.validate(request); + + assertThat(violations).isEmpty(); + } + + // --- Sad paths: recordId --- + + @Test + void nullRecordId_shouldProduceViolationWithCorrectMessage() { + var request = new CreateCommentRequest(null, "En giltig kommentar."); + + Set> violations = validator.validate(request); + + assertThat(violations).hasSize(1); + assertThat(violations.iterator().next().getMessage()).isEqualTo("Ärende måste anges"); + } + + // --- Sad paths: body --- + + @Test + void blankBody_shouldProduceViolationWithCorrectMessage() { + var request = new CreateCommentRequest(UUID.randomUUID(), " "); + + Set> violations = validator.validate(request); + + assertThat(violations).hasSize(1); + assertThat(violations.iterator().next().getMessage()).isEqualTo("Kommentar får inte vara tom"); + } + + @Test + void emptyBody_shouldProduceViolationWithCorrectMessage() { + var request = new CreateCommentRequest(UUID.randomUUID(), ""); + + Set> violations = validator.validate(request); + + assertThat(violations).hasSize(1); + assertThat(violations.iterator().next().getMessage()).isEqualTo("Kommentar får inte vara tom"); + } + + @Test + void nullBody_shouldProduceViolationWithCorrectMessage() { + var request = new CreateCommentRequest(UUID.randomUUID(), null); + + Set> violations = validator.validate(request); + + assertThat(violations).hasSize(1); + assertThat(violations.iterator().next().getMessage()).isEqualTo("Kommentar får inte vara tom"); + } + + @Test + void bodyExceeding5000Characters_shouldProduceViolationWithCorrectMessage() { + var request = new CreateCommentRequest(UUID.randomUUID(), "x".repeat(5001)); + + Set> violations = validator.validate(request); + + assertThat(violations).hasSize(1); + assertThat(violations.iterator().next().getMessage()).isEqualTo("Kommentar får max vara 5000 tecken"); + } + + @Test + void allFieldsInvalid_shouldProduceTwoViolations() { + var request = new CreateCommentRequest(null, ""); + + Set> violations = validator.validate(request); + + assertThat(violations).hasSize(2); + } +} diff --git a/src/test/java/org/example/vet1177/dto/request/comment/UpdateCommentRequestValidationTest.java b/src/test/java/org/example/vet1177/dto/request/comment/UpdateCommentRequestValidationTest.java new file mode 100644 index 00000000..ac71b921 --- /dev/null +++ b/src/test/java/org/example/vet1177/dto/request/comment/UpdateCommentRequestValidationTest.java @@ -0,0 +1,86 @@ +package org.example.vet1177.dto.request.comment; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +class UpdateCommentRequestValidationTest { + + private Validator validator; + + @BeforeEach + void setUp() { + try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) { + validator = factory.getValidator(); + } + } + + // --- Happy paths --- + + @Test + void validRequest_shouldProduceNoViolations() { + var request = new UpdateCommentRequest("Uppdaterad kommentar med ny information."); + + Set> violations = validator.validate(request); + + assertThat(violations).isEmpty(); + } + + @Test + void bodyWithExactly5000Characters_shouldProduceNoViolations() { + var request = new UpdateCommentRequest("x".repeat(5000)); + + Set> violations = validator.validate(request); + + assertThat(violations).isEmpty(); + } + + // --- Sad paths: body --- + + @Test + void blankBody_shouldProduceViolationWithCorrectMessage() { + var request = new UpdateCommentRequest(" "); + + Set> violations = validator.validate(request); + + assertThat(violations).hasSize(1); + assertThat(violations.iterator().next().getMessage()).isEqualTo("Kommentar får inte vara tom"); + } + + @Test + void emptyBody_shouldProduceViolationWithCorrectMessage() { + var request = new UpdateCommentRequest(""); + + Set> violations = validator.validate(request); + + assertThat(violations).hasSize(1); + assertThat(violations.iterator().next().getMessage()).isEqualTo("Kommentar får inte vara tom"); + } + + @Test + void nullBody_shouldProduceViolationWithCorrectMessage() { + var request = new UpdateCommentRequest(null); + + Set> violations = validator.validate(request); + + assertThat(violations).hasSize(1); + assertThat(violations.iterator().next().getMessage()).isEqualTo("Kommentar får inte vara tom"); + } + + @Test + void bodyExceeding5000Characters_shouldProduceViolationWithCorrectMessage() { + var request = new UpdateCommentRequest("x".repeat(5001)); + + Set> violations = validator.validate(request); + + assertThat(violations).hasSize(1); + assertThat(violations.iterator().next().getMessage()).isEqualTo("Kommentar får max vara 5000 tecken"); + } +} From c2b3cae5781e4a7563b9655e9ea2d7d7d2f31858 Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Sat, 4 Apr 2026 12:28:35 +0200 Subject: [PATCH 5/6] Add validation tests for `CreateCommentRequest` and `UpdateCommentRequest` - Introduced unit tests to validate fields and constraints in `CreateCommentRequest` and `UpdateCommentRequest`. - Covered both valid and invalid scenarios for request bodies and identifiers. Closes #110 Closes #96 --- .../vet1177/dto/response/comment/CommentResponseTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/org/example/vet1177/dto/response/comment/CommentResponseTest.java b/src/test/java/org/example/vet1177/dto/response/comment/CommentResponseTest.java index 4c8fe81f..235aa20b 100644 --- a/src/test/java/org/example/vet1177/dto/response/comment/CommentResponseTest.java +++ b/src/test/java/org/example/vet1177/dto/response/comment/CommentResponseTest.java @@ -24,6 +24,7 @@ class CommentResponseTest { private UUID authorId; private UUID recordId; + @BeforeEach void setUp() throws Exception { commentId = UUID.randomUUID(); From 7f34af51dd3a0b7971922af792451b02d5c9f47d Mon Sep 17 00:00:00 2001 From: Annika Holmqvist Date: Sun, 5 Apr 2026 12:46:01 +0200 Subject: [PATCH 6/6] Refactor validation tests to use `@BeforeAll` and `@AfterAll` for shared Validator setup and cleanup --- .../CreateCommentRequestValidationTest.java | 20 ++++++++++++------- .../UpdateCommentRequestValidationTest.java | 20 ++++++++++++------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/test/java/org/example/vet1177/dto/request/comment/CreateCommentRequestValidationTest.java b/src/test/java/org/example/vet1177/dto/request/comment/CreateCommentRequestValidationTest.java index c50b0d5f..5e3bc2ca 100644 --- a/src/test/java/org/example/vet1177/dto/request/comment/CreateCommentRequestValidationTest.java +++ b/src/test/java/org/example/vet1177/dto/request/comment/CreateCommentRequestValidationTest.java @@ -4,7 +4,8 @@ import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.util.Set; @@ -14,13 +15,18 @@ class CreateCommentRequestValidationTest { - private Validator validator; + private static ValidatorFactory factory; + private static Validator validator; - @BeforeEach - void setUp() { - try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) { - validator = factory.getValidator(); - } + @BeforeAll + static void setUp() { + factory = Validation.buildDefaultValidatorFactory(); + validator = factory.getValidator(); + } + + @AfterAll + static void tearDown() { + factory.close(); } // --- Happy paths --- diff --git a/src/test/java/org/example/vet1177/dto/request/comment/UpdateCommentRequestValidationTest.java b/src/test/java/org/example/vet1177/dto/request/comment/UpdateCommentRequestValidationTest.java index ac71b921..6dea760c 100644 --- a/src/test/java/org/example/vet1177/dto/request/comment/UpdateCommentRequestValidationTest.java +++ b/src/test/java/org/example/vet1177/dto/request/comment/UpdateCommentRequestValidationTest.java @@ -4,7 +4,8 @@ import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.util.Set; @@ -13,13 +14,18 @@ class UpdateCommentRequestValidationTest { - private Validator validator; + private static ValidatorFactory factory; + private static Validator validator; - @BeforeEach - void setUp() { - try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) { - validator = factory.getValidator(); - } + @BeforeAll + static void setUp() { + factory = Validation.buildDefaultValidatorFactory(); + validator = factory.getValidator(); + } + + @AfterAll + static void tearDown() { + factory.close(); } // --- Happy paths ---