1111import org .junit .jupiter .params .ParameterizedTest ;
1212import org .junit .jupiter .params .provider .Arguments ;
1313import org .junit .jupiter .params .provider .MethodSource ;
14+ import org .mockito .ArgumentCaptor ;
1415import org .mockito .InjectMocks ;
1516import org .mockito .Mock ;
1617import org .mockito .junit .jupiter .MockitoExtension ;
2122
2223import static org .junit .jupiter .api .Assertions .assertEquals ;
2324import static org .junit .jupiter .api .Assertions .assertNotNull ;
25+ import static org .junit .jupiter .api .Assertions .assertNull ;
2426import static org .junit .jupiter .api .Assertions .assertThrows ;
2527import static org .junit .jupiter .api .Assertions .assertTrue ;
2628import static org .mockito .ArgumentMatchers .any ;
@@ -256,15 +258,21 @@ void testCreateBook_SpecialCharactersInTitle_Success() {
256258 // Act
257259 Book result = testBookService .createBook (specialRequest );
258260
261+ // Assert: capture the Book passed to save()
262+ ArgumentCaptor <Book > bookCaptor = ArgumentCaptor .forClass (Book .class );
263+ verify (testBookRepository , times (1 )).save (bookCaptor .capture ());
264+ Book savedBook = bookCaptor .getValue ();
265+
259266 // Assert
260- assertNotNull (result );
261- assertEquals (testId , result .getId ());
262- assertEquals (specialRequest .title (), result .getTitle ());
263- assertEquals (specialRequest .synopsis (), result .getSynopsis ());
264- assertEquals (specialRequest .author (), result .getAuthor ());
267+ assertNotNull (savedBook );
268+ assertNull (savedBook .getId (), "ID should be null before DB generates it" );
269+ assertEquals (specialRequest .title (), savedBook .getTitle ());
270+ assertEquals (specialRequest .synopsis (), savedBook .getSynopsis ());
271+ assertEquals (specialRequest .author (), savedBook .getAuthor ());
272+
273+ // Assert: Verify the Service fulfills its return contract
274+ assertEquals (expectedBook , result , "Service must return the object returned by the repository" );
265275
266- // Did the service perform the correct action on its dependency?
267- verify (testBookRepository , times (1 )).save (any (Book .class ));
268276 }
269277
270278 // --------------------------------------------------------------------------------------------
@@ -274,13 +282,11 @@ void testCreateBook_SpecialCharactersInTitle_Success() {
274282 @ Test
275283 void testDelete_Book_ShouldThrowException_WhenIdNotFound () {
276284
277- // Arrange: As goal is to test what happens when the resource doesn't exist,
278- // we intentionally simulate DB returning NO result
285+ // Arrange: simulate missing record
279286 when (testBookRepository .findById (testId )).thenReturn (Optional .empty ());
280287
281- // ACT and ASSERT: throw ResourceNotFoundException when calling the delete method.
288+ // ACT and ASSERT: correct exception thrown
282289 assertThrows (
283- // custom exception to reflect business rules vs technical problem
284290 ResourceNotFoundException .class ,
285291 () -> testBookService .deleteBookById (testId )
286292 );
@@ -293,24 +299,30 @@ void testDelete_Book_ShouldThrowException_WhenIdNotFound() {
293299 @ Test
294300 void testDeleteBookById_Success () {
295301
296- // Arrange:
297- persistedBook .setDeleted (false ); // ensure starting state
302+ // Arrange: ensure the test book is active
303+ persistedBook .setDeleted (false );
298304
299305 when (testBookRepository .findById (testId ))
300306 .thenReturn (Optional .of (persistedBook ));
301307
302- when (testBookRepository .save (any (Book .class )))
303- .thenReturn (persistedBook );
304-
305308 // Act: call the service method we are testing
306309 testBookService .deleteBookById (testId );
307310
308311 // Assert: the entity was marked deleted
309- assertTrue (persistedBook .isDeleted ());
312+ ArgumentCaptor <Book > bookCaptor = ArgumentCaptor .forClass (Book .class );
313+ verify (testBookRepository , times (1 )).save (bookCaptor .capture ());
314+
315+ // extract from captured object (internal list)
316+ Book savedBook = bookCaptor .getValue ();
317+
318+ // Assert: the service correctly marked it as deleted
319+ assertTrue (
320+ savedBook .isDeleted (),
321+ "Book passed to save() should be marked deleted"
322+ );
323+ // Assert: it is the same ID we attempted to delete
324+ assertEquals (testId , savedBook .getId ());
310325
311- // Assert: repository methods were called correctly
312- verify (testBookRepository , times (1 )).findById (testId );
313- verify (testBookRepository , times (1 )).save (persistedBook );
314326 }
315327
316328 @ Test
0 commit comments