22
33import com .codesungrape .hmcts .bookapi .dto .BookRequest ;
44import com .codesungrape .hmcts .bookapi .entity .Book ;
5+ import com .codesungrape .hmcts .bookapi .exception .ResourceNotFoundException ;
56import com .codesungrape .hmcts .bookapi .repository .BookRepository ;
67import com .codesungrape .hmcts .bookapi .service .BookService ;
78import org .junit .jupiter .api .BeforeEach ;
1415import org .mockito .Mock ;
1516import org .mockito .junit .jupiter .MockitoExtension ;
1617
18+ import java .util .Optional ;
1719import java .util .UUID ;
1820import java .util .stream .Stream ;
1921
2022import static org .junit .jupiter .api .Assertions .assertEquals ;
2123import static org .junit .jupiter .api .Assertions .assertNotNull ;
2224import static org .junit .jupiter .api .Assertions .assertThrows ;
25+ import static org .junit .jupiter .api .Assertions .assertTrue ;
2326import static org .mockito .ArgumentMatchers .any ;
2427import static org .mockito .Mockito .never ;
2528import static org .mockito .Mockito .when ;
@@ -53,6 +56,10 @@ class BookServiceTest {
5356 private Book persistedBook ;
5457 private UUID testId ;
5558
59+ // --------------------------------------
60+ // Parameter Sources
61+ // --------------------------------------
62+
5663 // Provide test data, static method: can be called without creating an object.
5764 private static Stream <Arguments > provideLongFieldTestCases () {
5865 UUID testId = UUID .randomUUID ();
@@ -84,8 +91,9 @@ private static Stream<Arguments> provideLongFieldTestCases() {
8491 );
8592 }
8693
87- // --------- TESTS ------------
88-
94+ // --------------------------------------
95+ // Tests
96+ // --------------------------------------
8997 @ BeforeEach
9098 void setUp () {
9199 testId = UUID .randomUUID ();
@@ -109,6 +117,9 @@ void setUp() {
109117 .build ();
110118 }
111119
120+ // --------------------------------------
121+ // Tests: createBook
122+ // --------------------------------------
112123 @ Test
113124 void testCreateBook_Success () {
114125
@@ -192,7 +203,6 @@ void testCreateBook_BlankTitle_ThrowsException() {
192203 );
193204 }
194205
195- // --------- Repository failures
196206 @ Test
197207 void testCreateBook_RepositoryFailure_ThrowsException () {
198208 // Arrange
@@ -213,7 +223,10 @@ void testCreateBook_RepositoryFailure_ThrowsException() {
213223 @ ParameterizedTest (name = "{0}" ) // Display the test name
214224 @ MethodSource ("provideLongFieldTestCases" )
215225 void testCreateBook_VeryLongFields_Success (
216- String testName , BookRequest request , Book expectedBook ) {
226+ String testName ,
227+ BookRequest request ,
228+ Book expectedBook
229+ ) {
217230
218231 // Arrange
219232 when (testBookRepository .save (any (Book .class ))).thenReturn (expectedBook );
@@ -260,4 +273,50 @@ void testCreateBook_SpecialCharactersInTitle_Success() {
260273 // Did the service perform the correct action on its dependency?
261274 verify (testBookRepository , times (1 )).save (any (Book .class ));
262275 }
276+
277+ // --------------------------------------------------------------------------------------------
278+ // Tests: deleteBookById(UUID)
279+ // -------------------------------------------------------------------------------------------
280+
281+ @ Test
282+ void testDelete_Book_ShouldThrowException_WhenIdNotFound () {
283+
284+ // Arrange: As goal is to test what happens when the resource doesn't exist,
285+ // we intentionally simulate DB returning NO result
286+ when (testBookRepository .findByIdAndDeletedFalse (testId )).thenReturn (Optional .empty ());
287+
288+ // ACT and ASSERT: throw ResourceNotFoundException when calling the delete method.
289+ assertThrows (
290+ // custom exception to reflect business rules vs technical problem
291+ ResourceNotFoundException .class ,
292+ () -> testBookService .deleteBookById (testId )
293+ );
294+
295+ // Assert: ensure the save method was NEVER called.
296+ // proves delete business logic halts immediately when the resource isn't found.
297+ verify (testBookRepository , never ()).save (any (Book .class ));
298+ }
299+
300+ @ Test
301+ void testDeleteBookById_Success () {
302+
303+ // Arrange:
304+ persistedBook .setDeleted (false ); // ensure starting state
305+
306+ when (testBookRepository .findByIdAndDeletedFalse (testId ))
307+ .thenReturn (Optional .of (persistedBook ));
308+
309+ when (testBookRepository .save (any (Book .class )))
310+ .thenReturn (persistedBook );
311+
312+ // Act: call the service method we are testing
313+ testBookService .deleteBookById (testId );
314+
315+ // Assert: the entity was marked deleted
316+ assertTrue (persistedBook .isDeleted ());
317+
318+ // Assert: repository methods were called correctly
319+ verify (testBookRepository , times (1 )).findByIdAndDeletedFalse (testId );
320+ verify (testBookRepository , times (1 )).save (persistedBook );
321+ }
263322}
0 commit comments