diff --git a/.coderabbit.yaml b/.coderabbit.yaml index 2c072f6..df0c121 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -84,7 +84,7 @@ reviews: - Test classes should use JUnit 5 (Jupiter) - Verify proper Spring test annotations (@WebMvcTest, @DataJpaTest, etc.) - Check use of @MockitoBean (Spring Boot 4.0 style) - - Ensure test naming follows method_scenario_outcome pattern (concise) + - Ensure test naming follows givenX_whenY_thenZ BDD pattern - Validate BDD semantics in JavaDoc comments (Given/When/Then) - Validate use of AssertJ for fluent assertions - Check @DisplayName for readable test descriptions diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 8138ac3..3befb12 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -43,7 +43,7 @@ http://localhost:9001/actuator/health # Health check - **Validation**: Bean Validation annotations in DTOs (`@NotNull`, `@Min`, etc.) - **Caching**: Spring `@Cacheable` on service layer (1-hour TTL) - **DTO Pattern**: ModelMapper for entity ↔ DTO transformations -- **Repository**: Spring Data JPA with derived queries and custom JPQL +- **Repository**: Spring Data JPA with derived queries (prefer over custom JPQL) ## Code Conventions @@ -67,21 +67,21 @@ http://localhost:9001/actuator/health # Health check ## Testing - **Structure**: `*Tests.java` in `src/test/java/` (mirrors main package structure) -- **Naming Pattern**: `method_scenario_outcome` - - `method`: Method under test (e.g., `post`, `findById`, `create`) - - `scenario`: Context (e.g., `playerExists`, `invalidData`, `noMatches`) - - `outcome`: Expected result (e.g., `returnsPlayer`, `returnsConflict`, `returnsEmpty`) +- **Naming Pattern**: `givenX_whenY_thenZ` (BDD Given-When-Then) + - `given`: Preconditions/context (e.g., `givenPlayerExists`, `givenInvalidData`, `givenNoMatches`) + - `when`: Action being tested (e.g., `whenPost`, `whenFindById`, `whenCreate`) + - `then`: Expected outcome (e.g., `thenReturnsPlayer`, `thenReturnsConflict`, `thenReturnsEmpty`) - **Examples**: ```java // Controller - void post_squadNumberExists_returnsConflict() + void givenSquadNumberExists_whenPost_thenReturnsConflict() // Service - void create_noConflict_returnsPlayerDTO() + void givenNoConflict_whenCreate_thenReturnsPlayerDTO() // Repository - void findById_playerExists_returnsPlayer() + void givenPlayerExists_whenFindById_thenReturnsPlayer() ``` - **JavaDoc**: BDD Given/When/Then structure in test comments @@ -97,7 +97,7 @@ http://localhost:9001/actuator/health # Health check ``` - **Annotations**: `@SpringBootTest`, `@AutoConfigureMockMvc`, `@Test` -- **Assertions**: AssertJ (fluent, e.g., `assertThat(result).isNotNull()`) +- **Assertions**: AssertJ BDD style (e.g., `then(result).isNotNull()`) - **Mocking**: Mockito for service layer tests - **Database**: Tests use in-memory SQLite (auto-cleared after each test) - **Coverage**: Target high coverage (JaCoCo reports in `target/site/jacoco/`) diff --git a/README.md b/README.md index 3760bc5..b51f410 100644 --- a/README.md +++ b/README.md @@ -243,10 +243,10 @@ open target/site/jacoco/index.html - **Test Database** - SQLite in-memory (jdbc:sqlite::memory:) for fast, isolated test execution - **Mocking** - Mockito with `@MockitoBean` for dependency mocking - **Assertions** - AssertJ fluent assertions -- **Naming Convention** - `method_scenario_outcome` pattern: - - `getAll_playersExist_returnsOkWithAllPlayers()` - - `post_squadNumberExists_returnsConflict()` - - `findById_playerExists_returnsPlayer()` +- **Naming Convention** - `givenX_whenY_thenZ` BDD pattern: + - `givenPlayersExist_whenGetAll_thenReturnsOkWithAllPlayers()` + - `givenSquadNumberExists_whenPost_thenReturnsConflict()` + - `givenPlayerExists_whenFindById_thenReturnsPlayer()` **Coverage Targets:** diff --git a/src/main/java/ar/com/nanotaboada/java/samples/spring/boot/controllers/PlayersController.java b/src/main/java/ar/com/nanotaboada/java/samples/spring/boot/controllers/PlayersController.java index 267cd85..90f6418 100644 --- a/src/main/java/ar/com/nanotaboada/java/samples/spring/boot/controllers/PlayersController.java +++ b/src/main/java/ar/com/nanotaboada/java/samples/spring/boot/controllers/PlayersController.java @@ -39,7 +39,7 @@ *
+ * Returns the complete Argentina 2022 FIFA World Cup squad (26 players). + *
+ * + * @return 200 OK with array of all players (empty array if none found) + */ + @GetMapping("/players") + @Operation(summary = "Retrieves all players") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json", schema = @Schema(implementation = PlayerDTO[].class))) + }) + public ResponseEntity- * Returns the complete Argentina 2022 FIFA World Cup squad (26 players). + * Squad numbers are unique jersey numbers (e.g., Messi is #10). This is a direct lookup similar to getById(). + * Example: {@code /players/squadnumber/10} returns Lionel Messi *
* - * @return 200 OK with array of all players (empty array if none found) + * @param squadNumber the squad number to retrieve (jersey number, typically 1-99) + * @return 200 OK with player data, or 404 Not Found if no player has that number */ - @GetMapping("/players") - @Operation(summary = "Retrieves all players") + @GetMapping("/players/squadnumber/{squadNumber}") + @Operation(summary = "Retrieves a player by squad number") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json", schema = @Schema(implementation = PlayerDTO[].class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json", schema = @Schema(implementation = PlayerDTO.class))), + @ApiResponse(responseCode = "404", description = "Not Found", content = @Content) }) - public ResponseEntity- * Squad numbers are jersey numbers that users recognize (e.g., Messi is #10). - * Example: {@code /players/search/squadnumber/10} returns Lionel Messi - *
- * - * @param squadNumber the squad number to search for (jersey number, typically 1-99) - * @return 200 OK with player data, or 404 Not Found if no player has that - * number - */ - @GetMapping("/players/search/squadnumber/{squadNumber}") - @Operation(summary = "Searches for a player by squad number") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/json", schema = @Schema(implementation = PlayerDTO.class))), - @ApiResponse(responseCode = "404", description = "Not Found", content = @Content) - }) - public ResponseEntity- * This method uses a custom JPQL query with LIKE operator for partial matches. - * For example, searching for "Premier" will match "Premier League". - *
- * - * @param league the league name to search for (partial matches allowed) - * @return a list of players whose league name contains the search term (empty - * list if none found) - */ - @Query("SELECT p FROM Player p WHERE LOWER(p.league) LIKE LOWER(CONCAT('%', :league, '%'))") - List
@@ -67,4 +51,17 @@ public interface PlayersRepository extends JpaRepository
+ * This method uses Spring Data's derived query mechanism to perform partial matching.
+ * For example, searching for "Premier" will match "Premier League".
+ *
+ * This method returns the complete Argentina 2022 FIFA World Cup squad (26 players).
+ * Results are cached to improve performance on subsequent calls.
+ *
@@ -130,21 +148,21 @@ public PlayerDTO retrieveById(Long id) {
}
/**
- * Retrieves all players from the database.
+ * Retrieves a player by their squad number (unique identifier).
*
- * This method returns the complete Argentina 2022 FIFA World Cup squad (26 players).
- * Results are cached to improve performance on subsequent calls.
+ * Squad numbers are unique jersey numbers (e.g., Messi is #10). This is a direct lookup by unique identifier,
+ * similar to retrieveById(). Results are cached to improve performance.
*
- * This method performs an exact match on the squad number field. Squad numbers are jersey numbers that users recognize
- * (e.g., Messi is #10).
- * >() {
+ });
+ // Then
+ then(response.getContentType()).contains("application/json");
+ verify(playersServiceMock, times(1)).retrieveAll();
+ then(response.getStatus()).isEqualTo(HttpStatus.OK.value());
+ then(actual).usingRecursiveComparison().isEqualTo(expected);
}
/**
- * Given a player with ID 999 does not exist
- * When GET /players/999 is called and the service returns null
- * Then response status is 404 Not Found
+ * Given a player exists
+ * When requesting that player by ID
+ * Then response status is 200 OK and the player data is returned
*/
@Test
- void getById_playerNotFound_returnsNotFound()
+ void givenPlayerExists_whenGetById_thenReturnsOk()
throws Exception {
- // Arrange
- Long id = 999L;
+ // Given
+ PlayerDTO expected = PlayerDTOFakes.createOneForUpdate();
Mockito
- .when(playersServiceMock.retrieveById(anyLong()))
- .thenReturn(null);
+ .when(playersServiceMock.retrieveById(1L))
+ .thenReturn(expected);
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
- .get(PATH + "/{id}", id);
- // Act
+ .get(PATH + "/{id}", 1L);
+ // When
MockHttpServletResponse response = application
.perform(request)
.andReturn()
.getResponse();
- // Assert
- verify(playersServiceMock, times(1)).retrieveById(anyLong());
- assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
+ String content = response.getContentAsString();
+ PlayerDTO actual = objectMapper.readValue(content, PlayerDTO.class);
+ // Then
+ then(response.getContentType()).contains("application/json");
+ verify(playersServiceMock, times(1)).retrieveById(1L);
+ then(response.getStatus()).isEqualTo(HttpStatus.OK.value());
+ then(actual).usingRecursiveComparison().isEqualTo(expected);
}
/**
- * Given 26 players exist in the database
- * When GET /players is called and the service returns all players
- * Then response status is 200 OK and all 26 players are returned
+ * Given a player with a specific ID does not exist
+ * When requesting that player by ID
+ * Then response status is 404 Not Found
*/
@Test
- void getAll_playersExist_returnsOkWithAllPlayers()
+ void givenPlayerDoesNotExist_whenGetById_thenReturnsNotFound()
throws Exception {
- // Arrange
- List
>() {
- });
- // Assert
- assertThat(response.getContentType()).contains("application/json");
- verify(playersServiceMock, times(1)).retrieveAll();
- assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
- assertThat(result).hasSize(26);
- assertThat(result).usingRecursiveComparison().isEqualTo(playerDTOs);
+ // Then
+ verify(playersServiceMock, times(1)).retrieveById(anyLong());
+ then(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
}
/**
- * Given 7 players exist in Premier League
- * When GET /players/search/league/Premier is called and the service returns matching players
- * Then response status is 200 OK and 7 players are returned
+ * Given a player with a specific squad number exists
+ * When requesting that player by squad number
+ * Then response status is 200 OK and the player data is returned
*/
@Test
- void searchByLeague_matchingPlayersExist_returnsOkWithList()
+ void givenPlayerExists_whenGetBySquadNumber_thenReturnsOk()
throws Exception {
- // Arrange
- List
>() {
- });
- // Assert
- assertThat(response.getContentType()).contains("application/json");
- verify(playersServiceMock, times(1)).searchByLeague(any());
- assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
- assertThat(result).hasSize(7);
- assertThat(result).usingRecursiveComparison().isEqualTo(playerDTOs);
+ PlayerDTO actual = objectMapper.readValue(content, PlayerDTO.class);
+ // Then
+ then(response.getContentType()).contains("application/json");
+ verify(playersServiceMock, times(1)).retrieveBySquadNumber(squadNumber);
+ then(response.getStatus()).isEqualTo(HttpStatus.OK.value());
+ then(actual).usingRecursiveComparison().isEqualTo(expected);
+ then(actual.getSquadNumber()).isEqualTo(squadNumber);
}
/**
- * Given no players exist in "NonexistentLeague"
- * When GET /players/search/league/NonexistentLeague is called and the service returns an empty list
- * Then response status is 200 OK and an empty list is returned
+ * Given no player with a specific squad number exists
+ * When requesting a player by that squad number
+ * Then response status is 404 Not Found
*/
@Test
- void searchByLeague_noMatches_returnsOkWithEmptyList()
+ void givenPlayerDoesNotExist_whenGetBySquadNumber_thenReturnsNotFound()
throws Exception {
- // Arrange
+ // Given
+ Integer squadNumber = 99;
Mockito
- .when(playersServiceMock.searchByLeague(any()))
- .thenReturn(List.of());
+ .when(playersServiceMock.retrieveBySquadNumber(squadNumber))
+ .thenReturn(null);
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
- .get(PATH + "/search/league/{league}", "NonexistentLeague");
- // Act
+ .get(PATH + "/squadnumber/{squadNumber}", squadNumber);
+ // When
MockHttpServletResponse response = application
.perform(request)
.andReturn()
.getResponse();
- String content = response.getContentAsString();
- List
>() {
- });
- // Assert
- assertThat(response.getContentType()).contains("application/json");
- verify(playersServiceMock, times(1)).searchByLeague(any());
- assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
- assertThat(result).isEmpty();
+ // Then
+ verify(playersServiceMock, times(1)).retrieveBySquadNumber(squadNumber);
+ then(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
}
/**
- * Given a player with squad number 10 exists (Messi)
- * When GET /players/search/squadnumber/10 is called and the service returns the player
- * Then response status is 200 OK and the player data is returned
+ * Given players exist in a specific league
+ * When searching for players by league name
+ * Then response status is 200 OK and matching players are returned
*/
@Test
- void searchBySquadNumber_playerExists_returnsOkWithPlayer()
+ void givenPlayersExist_whenSearchByLeague_thenReturnsOk()
throws Exception {
- // Arrange
- PlayerDTO playerDTO = PlayerDTOFakes.createAll().stream()
- .filter(player -> player.getSquadNumber() == 10)
- .findFirst()
- .orElseThrow();
+ // Given
+ String league = "Premier";
+ List
>() {
+ });
+ // Then
+ then(response.getContentType()).contains("application/json");
+ verify(playersServiceMock, times(1)).searchByLeague(any());
+ then(response.getStatus()).isEqualTo(HttpStatus.OK.value());
+ then(actual).usingRecursiveComparison().isEqualTo(expected);
}
/**
- * Given no player with squad number 99 exists
- * When GET /players/search/squadnumber/99 is called and the service returns null
- * Then response status is 404 Not Found
+ * Given no players exist in a specific league
+ * When searching for players by that league name
+ * Then response status is 200 OK and an empty list is returned
*/
@Test
- void searchBySquadNumber_playerNotFound_returnsNotFound()
+ void givenNoPlayersExist_whenSearchByLeague_thenReturnsOk()
throws Exception {
- // Arrange
+ // Given
+ String league = "Nonexistent League";
Mockito
- .when(playersServiceMock.searchBySquadNumber(99))
- .thenReturn(null);
+ .when(playersServiceMock.searchByLeague(any()))
+ .thenReturn(List.of());
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
- .get(PATH + "/search/squadnumber/{squadNumber}", 99);
- // Act
+ .get(PATH + "/search/league/{league}", league);
+ // When
MockHttpServletResponse response = application
.perform(request)
.andReturn()
.getResponse();
- // Assert
- verify(playersServiceMock, times(1)).searchBySquadNumber(99);
- assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
+ String content = response.getContentAsString();
+ List
>() {
+ });
+ // Then
+ then(response.getContentType()).contains("application/json");
+ verify(playersServiceMock, times(1)).searchByLeague(any());
+ then(response.getStatus()).isEqualTo(HttpStatus.OK.value());
+ then(actual).isEmpty();
}
/*
@@ -374,145 +371,142 @@ void searchBySquadNumber_playerNotFound_returnsNotFound()
/**
* Given a player exists and valid update data is provided
- * When PUT /players/{id} is called and the service successfully updates the player
+ * When updating that player
* Then response status is 204 No Content
*/
@Test
- void put_playerExists_returnsNoContent()
+ void givenPlayerExists_whenPut_thenReturnsNoContent()
throws Exception {
- // Arrange
- PlayerDTO playerDTO = PlayerDTOFakes.createOneValid();
- playerDTO.setId(1L); // Set ID for update operation
- Long id = playerDTO.getId();
- String body = objectMapper.writeValueAsString(playerDTO);
+ // Given
+ PlayerDTO dto = PlayerDTOFakes.createOneValid();
+ dto.setId(1L); // Set ID for update operation
+ String content = objectMapper.writeValueAsString(dto);
Mockito
.when(playersServiceMock.update(any(PlayerDTO.class)))
.thenReturn(true);
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
- .put(PATH + "/{id}", id)
- .content(body)
+ .put(PATH + "/{id}", dto.getId())
+ .content(content)
.contentType(MediaType.APPLICATION_JSON);
- // Act
+ // When
MockHttpServletResponse response = application
.perform(request)
.andReturn()
.getResponse();
- // Assert
+ // Then
verify(playersServiceMock, times(1)).update(any(PlayerDTO.class));
- assertThat(response.getStatus()).isEqualTo(HttpStatus.NO_CONTENT.value());
+ then(response.getStatus()).isEqualTo(HttpStatus.NO_CONTENT.value());
}
/**
* Given a player with the provided ID does not exist
- * When PUT /players/{id} is called and the service returns false
+ * When attempting to update that player
* Then response status is 404 Not Found
*/
@Test
- void put_playerNotFound_returnsNotFound()
+ void givenPlayerDoesNotExist_whenPut_thenReturnsNotFound()
throws Exception {
- // Arrange
- PlayerDTO playerDTO = PlayerDTOFakes.createOneValid();
- playerDTO.setId(999L); // Set ID for update operation
- Long id = playerDTO.getId();
- String body = objectMapper.writeValueAsString(playerDTO);
+ // Given
+ PlayerDTO dto = PlayerDTOFakes.createOneValid();
+ dto.setId(999L); // Set ID for update operation
+ String content = objectMapper.writeValueAsString(dto);
Mockito
.when(playersServiceMock.update(any(PlayerDTO.class)))
.thenReturn(false);
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
- .put(PATH + "/{id}", id)
- .content(body)
+ .put(PATH + "/{id}", dto.getId())
+ .content(content)
.contentType(MediaType.APPLICATION_JSON);
- // Act
+ // When
MockHttpServletResponse response = application
.perform(request)
.andReturn()
.getResponse();
- // Assert
+ // Then
verify(playersServiceMock, times(1)).update(any(PlayerDTO.class));
- assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
+ then(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
}
/**
* Given invalid player data is provided (validation fails)
- * When PUT /players/{id} is called
+ * When attempting to update a player
* Then response status is 400 Bad Request and service is never called
*/
@Test
- void put_invalidPlayer_returnsBadRequest()
+ void givenInvalidPlayer_whenPut_thenReturnsBadRequest()
throws Exception {
- // Arrange
- PlayerDTO playerDTO = PlayerDTOFakes.createOneInvalid();
- Long id = playerDTO.getId();
- String body = objectMapper.writeValueAsString(playerDTO);
+ // Given
+ PlayerDTO dto = PlayerDTOFakes.createOneInvalid();
+ String content = objectMapper.writeValueAsString(dto);
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
- .put(PATH + "/{id}", id)
- .content(body)
+ .put(PATH + "/{id}", dto.getId())
+ .content(content)
.contentType(MediaType.APPLICATION_JSON);
- // Act
+ // When
MockHttpServletResponse response = application
.perform(request)
.andReturn()
.getResponse();
- // Assert
+ // Then
verify(playersServiceMock, never()).update(any(PlayerDTO.class));
- assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value());
+ then(response.getStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
/**
* Given the path ID does not match the body ID
- * When PUT /players/{id} is called
+ * When attempting to update a player
* Then response status is 400 Bad Request and service is never called
*/
@Test
- void put_idMismatch_returnsBadRequest()
+ void givenIdMismatch_whenPut_thenReturnsBadRequest()
throws Exception {
- // Arrange
- PlayerDTO playerDTO = PlayerDTOFakes.createOneValid();
- playerDTO.setId(999L); // Body has different ID
+ // Given
+ PlayerDTO dto = PlayerDTOFakes.createOneValid();
+ dto.setId(999L); // Body has different ID
Long pathId = 1L; // Path has different ID
- String body = objectMapper.writeValueAsString(playerDTO);
+ String content = objectMapper.writeValueAsString(dto);
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
.put(PATH + "/{id}", pathId)
- .content(body)
+ .content(content)
.contentType(MediaType.APPLICATION_JSON);
- // Act
+ // When
MockHttpServletResponse response = application
.perform(request)
.andReturn()
.getResponse();
- // Assert
+ // Then
verify(playersServiceMock, never()).update(any(PlayerDTO.class));
- assertThat(response.getStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value());
+ then(response.getStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value());
}
/**
* Given the body ID is null (ID only in path)
- * When PUT /players/{id} is called
+ * When updating a player
* Then the ID is set from the path and the update proceeds normally
*/
@Test
- void put_nullBodyId_setsIdFromPath()
+ void givenNullBodyId_whenPut_thenSetsIdFromPath()
throws Exception {
- // Arrange
- PlayerDTO playerDTO = PlayerDTOFakes.createOneValid();
- playerDTO.setId(null); // Body has null ID
+ // Given
+ PlayerDTO dto = PlayerDTOFakes.createOneValid();
+ dto.setId(null); // Body has null ID
Long pathId = 1L;
- String body = objectMapper.writeValueAsString(playerDTO);
+ String content = objectMapper.writeValueAsString(dto);
Mockito
.when(playersServiceMock.update(any(PlayerDTO.class)))
.thenReturn(true);
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
.put(PATH + "/{id}", pathId)
- .content(body)
+ .content(content)
.contentType(MediaType.APPLICATION_JSON);
- // Act
+ // When
MockHttpServletResponse response = application
.perform(request)
.andReturn()
.getResponse();
- // Assert
+ // Then
verify(playersServiceMock, times(1)).update(any(PlayerDTO.class));
- assertThat(response.getStatus()).isEqualTo(HttpStatus.NO_CONTENT.value());
+ then(response.getStatus()).isEqualTo(HttpStatus.NO_CONTENT.value());
}
/*
@@ -522,52 +516,51 @@ void put_nullBodyId_setsIdFromPath()
*/
/**
- * Given a player with ID 1 exists
- * When DELETE /players/1 is called and the service successfully deletes the player
+ * Given a player exists
+ * When deleting that player by ID
* Then response status is 204 No Content
*/
@Test
- void delete_playerExists_returnsNoContent()
+ void givenPlayerExists_whenDelete_thenReturnsNoContent()
throws Exception {
- // Arrange
- Long id = 1L;
+ // Given
Mockito
- .when(playersServiceMock.delete(anyLong()))
+ .when(playersServiceMock.delete(1L))
.thenReturn(true);
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
- .delete(PATH + "/{id}", id);
- // Act
+ .delete(PATH + "/{id}", 1L);
+ // When
MockHttpServletResponse response = application
.perform(request)
.andReturn()
.getResponse();
- // Assert
- verify(playersServiceMock, times(1)).delete(anyLong());
- assertThat(response.getStatus()).isEqualTo(HttpStatus.NO_CONTENT.value());
+ // Then
+ verify(playersServiceMock, times(1)).delete(1L);
+ then(response.getStatus()).isEqualTo(HttpStatus.NO_CONTENT.value());
}
/**
- * Given a player with ID 999 does not exist
- * When DELETE /players/999 is called and the service returns false
+ * Given a player with a specific ID does not exist
+ * When attempting to delete that player by ID
* Then response status is 404 Not Found
*/
@Test
- void delete_playerNotFound_returnsNotFound()
+ void givenPlayerDoesNotExist_whenDelete_thenReturnsNotFound()
throws Exception {
- // Arrange
+ // Given
Long id = 999L;
Mockito
- .when(playersServiceMock.delete(anyLong()))
+ .when(playersServiceMock.delete(id))
.thenReturn(false);
MockHttpServletRequestBuilder request = MockMvcRequestBuilders
.delete(PATH + "/{id}", id);
- // Act
+ // When
MockHttpServletResponse response = application
.perform(request)
.andReturn()
.getResponse();
- // Assert
- verify(playersServiceMock, times(1)).delete(anyLong());
- assertThat(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
+ // Then
+ verify(playersServiceMock, times(1)).delete(id);
+ then(response.getStatus()).isEqualTo(HttpStatus.NOT_FOUND.value());
}
}
diff --git a/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/repositories/PlayersRepositoryTests.java b/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/repositories/PlayersRepositoryTests.java
index 529a6cb..8ee6b04 100644
--- a/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/repositories/PlayersRepositoryTests.java
+++ b/src/test/java/ar/com/nanotaboada/java/samples/spring/boot/test/repositories/PlayersRepositoryTests.java
@@ -1,6 +1,6 @@
package ar.com.nanotaboada.java.samples.spring.boot.test.repositories;
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.BDDAssertions.then;
import java.util.List;
import java.util.Optional;
@@ -27,88 +27,97 @@ class PlayersRepositoryTests {
private PlayersRepository repository;
/**
- * Given Leandro Paredes is created and saved to the database with an auto-generated ID
- * When findById() is called with that ID
+ * Given a player exists in the database
+ * When findById() is called with that player's ID
* Then the player is returned
*/
@Test
- void findById_playerExists_returnsPlayer() {
- // Arrange
- Player leandro = PlayerFakes.createOneValid();
- Player saved = repository.save(leandro);
- // Act
- Optional