-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: integration tests example with extensions
- Loading branch information
Jonathan Henrique Medeiros
committed
Jun 27, 2024
1 parent
9541aef
commit ab46d06
Showing
13 changed files
with
368 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
src/main/resources/db/migration/V0001__inialize-database-schema.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
SET foreign_key_checks = 0; | ||
|
||
TRUNCATE TABLE billionaire; | ||
TRUNCATE TABLE billionaires; | ||
|
||
SET foreign_key_checks = 1; | ||
|
||
INSERT INTO billionaire (first_name, last_name, career, idempotency_id) VALUES ('Aliko', 'Dangote', 'Billionaire Industrialist', UUID()), | ||
('Bill', 'Gates', 'Billionaire Tech Entrepreneur', UUID()), | ||
('Folrunsho', 'Alakija', 'Billionaire Oil Magnate', UUID()); | ||
INSERT INTO billionaires (first_name, last_name, career, idempotency_id) VALUES ('Aliko', 'Dangote', 'Billionaire Industrialist', UUID()), | ||
('Bill', 'Gates', 'Billionaire Tech Entrepreneur', UUID()), | ||
('Folrunsho', 'Alakija', 'Billionaire Oil Magnate', UUID()); |
35 changes: 35 additions & 0 deletions
35
src/test/java/br/com/multidatasources/CleanupDatabaseExtension.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package br.com.multidatasources; | ||
|
||
import org.junit.jupiter.api.extension.BeforeEachCallback; | ||
import org.junit.jupiter.api.extension.ExtensionContext; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.repository.CrudRepository; | ||
import org.springframework.stereotype.Repository; | ||
import org.springframework.test.context.ActiveProfiles; | ||
import org.springframework.test.context.junit.jupiter.SpringExtension; | ||
|
||
import java.util.Map; | ||
|
||
@ActiveProfiles("integration-test") | ||
public class CleanupDatabaseExtension implements BeforeEachCallback { | ||
|
||
@Override | ||
public void beforeEach(final ExtensionContext context) { | ||
final var applicationContext = SpringExtension.getApplicationContext(context); | ||
final var repositoryBeans = applicationContext.getBeansWithAnnotation(Repository.class); | ||
cleanupDatabase(repositoryBeans); | ||
} | ||
|
||
private static void cleanupDatabase(final Map<String, Object> repositoryBeans) { | ||
repositoryBeans.values().forEach(CleanupDatabaseExtension::deleteAll); | ||
} | ||
|
||
private static void deleteAll(final Object repository) { | ||
switch (repository) { | ||
case JpaRepository<?, ?> jpaRepository -> jpaRepository.deleteAllInBatch(); | ||
case CrudRepository<?, ?> crudRepository -> crudRepository.deleteAll(); | ||
default -> throw new IllegalArgumentException("Unsupported repository type: " + repository.getClass()); | ||
} | ||
} | ||
|
||
} |
36 changes: 36 additions & 0 deletions
36
src/test/java/br/com/multidatasources/DatabaseRepositoryIntegrationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package br.com.multidatasources; | ||
|
||
import br.com.multidatasources.config.datasource.DataSourceRoutingConfiguration; | ||
import br.com.multidatasources.config.datasource.master.MasterDataSourceConfiguration; | ||
import br.com.multidatasources.config.datasource.replica.ReplicaDataSourceConfiguration; | ||
import br.com.multidatasources.config.properties.datasource.DataSourceConnectionPropertiesConfiguration; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; | ||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; | ||
import org.springframework.context.annotation.Import; | ||
import org.springframework.test.context.ActiveProfiles; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Inherited; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Target(ElementType.TYPE) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Inherited | ||
@ActiveProfiles("integration-test") | ||
@DataJpaTest | ||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) | ||
@ExtendWith(CleanupDatabaseExtension.class) | ||
@Import( | ||
value = { | ||
MasterDataSourceConfiguration.class, | ||
ReplicaDataSourceConfiguration.class, | ||
DataSourceRoutingConfiguration.class, | ||
DataSourceConnectionPropertiesConfiguration.class | ||
} | ||
) | ||
public @interface DatabaseRepositoryIntegrationTest { | ||
|
||
} |
19 changes: 19 additions & 0 deletions
19
src/test/java/br/com/multidatasources/DefaultBillionaire.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package br.com.multidatasources; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
import java.util.UUID; | ||
|
||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target(ElementType.PARAMETER) | ||
public @interface DefaultBillionaire { | ||
|
||
String firstName() default "John"; | ||
|
||
String lastName() default "Doe"; | ||
|
||
String career() default "SWE"; | ||
|
||
} |
47 changes: 47 additions & 0 deletions
47
src/test/java/br/com/multidatasources/DefaultBillionaireParameterResolverExtension.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package br.com.multidatasources; | ||
|
||
import br.com.multidatasources.model.Billionaire; | ||
import br.com.multidatasources.model.factory.BillionaireBuilder; | ||
import org.junit.jupiter.api.extension.ExtensionContext; | ||
import org.junit.jupiter.api.extension.ParameterContext; | ||
import org.junit.jupiter.api.extension.ParameterResolutionException; | ||
import org.junit.jupiter.api.extension.ParameterResolver; | ||
|
||
import java.lang.reflect.Parameter; | ||
import java.util.Optional; | ||
|
||
public class DefaultBillionaireParameterResolverExtension implements ParameterResolver { | ||
|
||
@Override | ||
public boolean supportsParameter(final ParameterContext parameterContext, final ExtensionContext extensionContext) throws ParameterResolutionException { | ||
return parameterContext.isAnnotated(DefaultBillionaire.class); | ||
} | ||
|
||
@Override | ||
public Object resolveParameter(final ParameterContext parameterContext, final ExtensionContext extensionContext) throws ParameterResolutionException { | ||
return defaultBillionaire(parameterContext.getParameter()); | ||
} | ||
|
||
private static Billionaire defaultBillionaire(final Parameter parameter) { | ||
if (parameter.getType() != Billionaire.class) { | ||
throw new IllegalArgumentException("Parameter must be of type Billionaire"); | ||
} | ||
|
||
final var firstName = Optional.ofNullable(parameter.getAnnotation(DefaultBillionaire.class)) | ||
.map(DefaultBillionaire::firstName) | ||
.orElse("John"); | ||
final var lastName = Optional.ofNullable(parameter.getAnnotation(DefaultBillionaire.class)) | ||
.map(DefaultBillionaire::lastName) | ||
.orElse("Doe"); | ||
final var career = Optional.ofNullable(parameter.getAnnotation(DefaultBillionaire.class)) | ||
.map(DefaultBillionaire::career) | ||
.orElse("Doe"); | ||
|
||
return BillionaireBuilder.builder() | ||
.firstName(firstName) | ||
.lastName(lastName) | ||
.career(career) | ||
.build(); | ||
} | ||
|
||
} |
31 changes: 31 additions & 0 deletions
31
src/test/java/br/com/multidatasources/IntegrationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package br.com.multidatasources; | ||
|
||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; | ||
import org.springframework.core.annotation.AliasFor; | ||
import org.springframework.test.context.ActiveProfiles; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Inherited; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Target(ElementType.TYPE) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Inherited | ||
@ActiveProfiles("integration-test") | ||
@SpringBootTest( | ||
webEnvironment = WebEnvironment.NONE | ||
) | ||
@ExtendWith(CleanupDatabaseExtension.class) | ||
public @interface IntegrationTest { | ||
|
||
@AliasFor(annotation = SpringBootTest.class, attribute = "classes") | ||
Class<?>[] classes() default {}; | ||
|
||
@AliasFor(annotation = SpringBootTest.class, attribute = "properties") | ||
String[] properties() default {}; | ||
|
||
} |
42 changes: 42 additions & 0 deletions
42
src/test/java/br/com/multidatasources/repository/BillionaireRepositoryIntegrationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package br.com.multidatasources.repository; | ||
|
||
import br.com.multidatasources.DatabaseRepositoryIntegrationTest; | ||
import br.com.multidatasources.model.factory.BillionaireBuilder; | ||
import br.com.multidatasources.service.v1.idempotency.impl.UUIDIdempotencyGenerator; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
|
||
import java.util.UUID; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
@DatabaseRepositoryIntegrationTest | ||
class BillionaireRepositoryIntegrationTest { | ||
|
||
@Autowired | ||
private BillionaireRepository billionaireRepository; | ||
|
||
@Test | ||
void givenExistentIdempotencyId_whenExistsBillionaireByIdempotencyId_thenReturnTrue() { | ||
final var idempotencyGenerator = new UUIDIdempotencyGenerator(); | ||
final var billionaire = BillionaireBuilder.builder() | ||
.firstName("John") | ||
.lastName("Doe") | ||
.career("SWE") | ||
.build(); | ||
|
||
billionaire.generateIdempotencyId(idempotencyGenerator); | ||
this.billionaireRepository.save(billionaire); | ||
|
||
final var actual = this.billionaireRepository.existsBillionaireByIdempotencyId(billionaire.getIdempotencyId()); | ||
|
||
assertThat(actual).isTrue(); | ||
} | ||
|
||
@Test | ||
void givenANonExistentIdempotencyId_whenExistsBillionaireByIdempotencyId_thenReturnFalse() { | ||
final var actual = this.billionaireRepository.existsBillionaireByIdempotencyId(UUID.randomUUID()); | ||
assertThat(actual).isFalse(); | ||
} | ||
|
||
} |
106 changes: 106 additions & 0 deletions
106
src/test/java/br/com/multidatasources/service/v1/BillionaireServiceIntegrationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package br.com.multidatasources.service.v1; | ||
|
||
import br.com.multidatasources.DefaultBillionaire; | ||
import br.com.multidatasources.DefaultBillionaireParameterResolverExtension; | ||
import br.com.multidatasources.IntegrationTest; | ||
import br.com.multidatasources.model.Billionaire; | ||
import br.com.multidatasources.repository.BillionaireRepository; | ||
import br.com.multidatasources.service.v1.idempotency.IdempotencyGenerator; | ||
import br.com.multidatasources.service.v1.idempotency.impl.UUIDIdempotencyGenerator; | ||
import jakarta.persistence.EntityNotFoundException; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.mock.mockito.SpyBean; | ||
|
||
import java.util.List; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
import static org.mockito.Mockito.verify; | ||
|
||
@IntegrationTest | ||
@ExtendWith(DefaultBillionaireParameterResolverExtension.class) | ||
class BillionaireServiceIntegrationTest { | ||
|
||
@SpyBean | ||
private IdempotencyGenerator idempotencyGenerator; | ||
|
||
@Autowired | ||
@SpyBean | ||
private BillionaireRepository billionaireRepository; | ||
|
||
@Autowired | ||
private BillionaireService billionaireService; | ||
|
||
@Test | ||
void givenAValidBillionaireId_whenFindBillionaireById_thenReturnASameBillionaireInformed(@DefaultBillionaire final Billionaire billionaire) { | ||
final var localIdempotencyGenerator = new UUIDIdempotencyGenerator(); | ||
billionaire.generateIdempotencyId(localIdempotencyGenerator); | ||
final var persistedBillionaire = this.billionaireRepository.saveAndFlush(billionaire); | ||
|
||
final var actual = this.billionaireService.findById(persistedBillionaire.getId()); | ||
|
||
assertThat(actual) | ||
.usingRecursiveComparison() | ||
.isEqualTo(persistedBillionaire); | ||
|
||
verify(this.billionaireRepository).findById(persistedBillionaire.getId()); | ||
} | ||
|
||
@Test | ||
void givenAInvalidBillionaireId_whenFindBillionaireById_thenThrowEntityNotFoundException() { | ||
final var invalidBillionaireId = 0L; | ||
|
||
assertThatThrownBy(() -> this.billionaireService.findById(invalidBillionaireId)) | ||
.isInstanceOf(EntityNotFoundException.class) | ||
.hasMessage("Register with id 0 not found"); | ||
|
||
verify(this.billionaireRepository).findById(invalidBillionaireId); | ||
} | ||
|
||
@Test | ||
void givenATwoBillionaires_whenFindAll_thenReturnListWithTwoRegistries( | ||
@DefaultBillionaire final Billionaire billionaireOne, | ||
@DefaultBillionaire(firstName = "Jake") final Billionaire billionaireTwo | ||
) { | ||
final var localIdempotencyGenerator = new UUIDIdempotencyGenerator(); | ||
billionaireOne.generateIdempotencyId(localIdempotencyGenerator); | ||
billionaireTwo.generateIdempotencyId(localIdempotencyGenerator); | ||
this.billionaireRepository.saveAllAndFlush(List.of(billionaireOne, billionaireTwo)); | ||
|
||
final var actual = this.billionaireService.findAll(); | ||
|
||
assertThat(actual) | ||
.hasSize(2) | ||
.usingRecursiveFieldByFieldElementComparator() | ||
.containsExactlyInAnyOrder(billionaireOne, billionaireTwo); | ||
|
||
verify(this.billionaireRepository).findAll(); | ||
} | ||
|
||
@Test | ||
void givenEmptyDataBillionaires_whenFindAll_thenReturnListWithZeroRegistries() { | ||
final var actual = this.billionaireService.findAll(); | ||
assertThat(actual).isEmpty(); | ||
verify(this.billionaireRepository).findAll(); | ||
} | ||
|
||
@Test | ||
void givenANewBillionaire_whenSave_thenReturnASameBillionaireSaved(@DefaultBillionaire final Billionaire billionaire) { | ||
final var localIdempotencyGenerator = new UUIDIdempotencyGenerator(); | ||
billionaire.generateIdempotencyId(localIdempotencyGenerator); | ||
|
||
final var actual = this.billionaireService.save(billionaire); | ||
|
||
assertThat(actual) | ||
.usingRecursiveComparison() | ||
.ignoringFields("id") | ||
.isEqualTo(billionaire); | ||
|
||
verify(this.idempotencyGenerator).generate(billionaire); | ||
verify(this.billionaireRepository).existsBillionaireByIdempotencyId(billionaire.getIdempotencyId()); | ||
verify(this.billionaireRepository).save(billionaire); | ||
} | ||
|
||
} |
Oops, something went wrong.