-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
enhancement/adding-test-cases
- Loading branch information
Showing
8 changed files
with
584 additions
and
0 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
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,38 @@ | ||
package com.behl.cachetropolis; | ||
|
||
import org.junit.jupiter.api.extension.BeforeAllCallback; | ||
import org.junit.jupiter.api.extension.ExtensionContext; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.testcontainers.containers.GenericContainer; | ||
import org.testcontainers.utility.DockerImageName; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import net.bytebuddy.utility.RandomString; | ||
|
||
@Slf4j | ||
@Configuration | ||
public class CacheExtension implements BeforeAllCallback { | ||
|
||
private static final int REDIS_PORT = 6379; | ||
private static final String REDIS_PASSWORD = RandomString.make(10); | ||
private static final DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:7.2.3-alpine"); | ||
|
||
private static final GenericContainer<?> redisContainer = new GenericContainer<>(REDIS_IMAGE) | ||
.withExposedPorts(REDIS_PORT) | ||
.withCommand("redis-server", "--requirepass", REDIS_PASSWORD); | ||
|
||
@Override | ||
public void beforeAll(final ExtensionContext context) { | ||
log.info("Creating cache container : {}", REDIS_IMAGE); | ||
redisContainer.start(); | ||
addCacheProperties(); | ||
log.info("Successfully started cache container : {}", REDIS_IMAGE); | ||
} | ||
|
||
private void addCacheProperties() { | ||
System.setProperty("spring.data.redis.host", redisContainer.getHost()); | ||
System.setProperty("spring.data.redis.port", String.valueOf(redisContainer.getMappedPort(REDIS_PORT))); | ||
System.setProperty("spring.data.redis.password", REDIS_PASSWORD); | ||
} | ||
|
||
} |
32 changes: 32 additions & 0 deletions
32
src/test/java/com/behl/cachetropolis/DataSourceExtension.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,32 @@ | ||
package com.behl.cachetropolis; | ||
|
||
import org.junit.jupiter.api.extension.BeforeAllCallback; | ||
import org.junit.jupiter.api.extension.ExtensionContext; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.testcontainers.containers.MySQLContainer; | ||
import org.testcontainers.utility.DockerImageName; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
|
||
@Slf4j | ||
@Configuration | ||
public class DataSourceExtension implements BeforeAllCallback { | ||
|
||
private static final DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:8"); | ||
private static final MySQLContainer<?> mySQLContainer = new MySQLContainer<>(MYSQL_IMAGE); | ||
|
||
@Override | ||
public void beforeAll(final ExtensionContext context) { | ||
log.info("Creating datasource container : {}", MYSQL_IMAGE); | ||
mySQLContainer.start(); | ||
addDataSourceProperties(); | ||
log.info("Successfully started datasource container : {}", MYSQL_IMAGE); | ||
} | ||
|
||
private void addDataSourceProperties() { | ||
System.setProperty("spring.datasource.url", mySQLContainer.getJdbcUrl()); | ||
System.setProperty("spring.datasource.username", mySQLContainer.getUsername()); | ||
System.setProperty("spring.datasource.password", mySQLContainer.getPassword()); | ||
} | ||
|
||
} |
63 changes: 63 additions & 0 deletions
63
src/test/java/com/behl/cachetropolis/repository/MasterHouseRepositoryTest.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,63 @@ | ||
package com.behl.cachetropolis.repository; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import java.util.UUID; | ||
|
||
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.autoconfigure.jdbc.AutoConfigureTestDatabase; | ||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; | ||
|
||
import com.behl.cachetropolis.DataSourceExtension; | ||
import com.behl.cachetropolis.entity.MasterHouse; | ||
|
||
import junit.framework.AssertionFailedError; | ||
|
||
@DataJpaTest | ||
@ExtendWith(DataSourceExtension.class) | ||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) | ||
class MasterHouseRepositoryTest { | ||
|
||
@Autowired | ||
private MasterHouseRepository masterHouseRepository; | ||
|
||
@Test | ||
void shouldFetchRandomHouseRecordFromDataSource() { | ||
// Fetch random house record from data source | ||
Optional<MasterHouse> masterHouse = masterHouseRepository.fetchRandom(); | ||
|
||
// assert fetched record's attributes | ||
assertThat(masterHouse).isPresent().get().satisfies(house -> { | ||
assertThat(house.getId()).isNotNull(); | ||
assertThat(house.getName()).isNotNull(); | ||
assertThat(house.getCreatedAt()).isNotNull(); | ||
assertThat(house.getUpdatedAt()).isNotNull(); | ||
}); | ||
} | ||
|
||
@Test | ||
void shouldNotFetchSameHouseRecordForEachInvocation() { | ||
// Retrieve IDs of all houses present in the data source | ||
final List<UUID> houseIds = masterHouseRepository.findAll().stream().map(MasterHouse::getId).toList(); | ||
assertThat(houseIds).isNotEmpty().hasSizeGreaterThan(1); | ||
|
||
// invoke method under test multiple times | ||
final var batchSize = 100; | ||
final List<MasterHouse> masterHouses = new ArrayList<MasterHouse>(); | ||
for (int i = 0; i < batchSize; i++) { | ||
final var masterHouse = masterHouseRepository.fetchRandom().orElseThrow(AssertionFailedError::new); | ||
masterHouses.add(masterHouse); | ||
} | ||
|
||
// Ensure randomly fetched houses contains all house-ids present in datasource | ||
final var totalHouses = houseIds.size(); | ||
List<UUID> uniqueHouseIds = masterHouses.stream().map(MasterHouse::getId).distinct().toList(); | ||
assertThat(uniqueHouseIds).hasSize(totalHouses).containsAll(houseIds); | ||
} | ||
|
||
} |
64 changes: 64 additions & 0 deletions
64
src/test/java/com/behl/cachetropolis/repository/WizardRepositoryTest.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,64 @@ | ||
package com.behl.cachetropolis.repository; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import java.util.List; | ||
import java.util.UUID; | ||
|
||
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.autoconfigure.jdbc.AutoConfigureTestDatabase; | ||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; | ||
|
||
import com.behl.cachetropolis.DataSourceExtension; | ||
import com.behl.cachetropolis.entity.Wizard; | ||
|
||
import junit.framework.AssertionFailedError; | ||
import net.bytebuddy.utility.RandomString; | ||
|
||
@DataJpaTest | ||
@ExtendWith(DataSourceExtension.class) | ||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) | ||
class WizardRepositoryTest { | ||
|
||
@Autowired | ||
private WizardRepository wizardRepository; | ||
|
||
@Autowired | ||
private MasterHouseRepository masterHouseRepository; | ||
|
||
@Test | ||
void shouldReturnWizardListByHouseId() { | ||
// fetch random house record from datasource | ||
final var masterHouse = masterHouseRepository.fetchRandom().orElseThrow(AssertionFailedError::new); | ||
final var houseId = masterHouse.getId(); | ||
|
||
// creare wizard record corresponding to fetched house | ||
final var wizard = new Wizard(); | ||
final var firstName = RandomString.make(); | ||
wizard.setFirstName(firstName); | ||
wizard.setGender("Male"); | ||
wizard.setHouseId(houseId); | ||
wizardRepository.save(wizard); | ||
|
||
// invoke method under test | ||
List<Wizard> wizards = wizardRepository.findByHouseId(houseId); | ||
|
||
// assert datasource response contains saved wizard record | ||
assertThat(wizards).isNotEmpty().map(Wizard::getFirstName).contains(firstName); | ||
} | ||
|
||
@Test | ||
void shouldReturnEmptyWizardListForInvalidHouseId() { | ||
// generate random house-id | ||
final var invalidHouseId = UUID.randomUUID(); | ||
|
||
// invoke method under test | ||
List<Wizard> wizards = wizardRepository.findByHouseId(invalidHouseId); | ||
|
||
// assert datasource response is empty list | ||
assertThat(wizards).isEmpty(); | ||
} | ||
|
||
} |
139 changes: 139 additions & 0 deletions
139
src/test/java/com/behl/cachetropolis/service/MasterHouseServiceTest.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,139 @@ | ||
package com.behl.cachetropolis.service; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
import static org.mockito.Mockito.times; | ||
import static org.mockito.Mockito.verify; | ||
|
||
import java.util.List; | ||
import java.util.UUID; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.mockito.Mockito; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.boot.test.mock.mockito.SpyBean; | ||
import org.springframework.cache.CacheManager; | ||
|
||
import com.behl.cachetropolis.CacheExtension; | ||
import com.behl.cachetropolis.DataSourceExtension; | ||
import com.behl.cachetropolis.dto.HouseDto; | ||
import com.behl.cachetropolis.dto.WizardDto; | ||
import com.behl.cachetropolis.entity.Wizard; | ||
import com.behl.cachetropolis.exception.InvalidHouseIdException; | ||
import com.behl.cachetropolis.repository.MasterHouseRepository; | ||
import com.behl.cachetropolis.repository.WizardRepository; | ||
|
||
import junit.framework.AssertionFailedError; | ||
import net.bytebuddy.utility.RandomString; | ||
|
||
@SpringBootTest | ||
@ExtendWith({ DataSourceExtension.class, CacheExtension.class }) | ||
class MasterHouseServiceTest { | ||
|
||
@Autowired | ||
private MasterHouseService masterHouseService; | ||
|
||
@SpyBean | ||
private WizardRepository wizardRepository; | ||
|
||
@SpyBean | ||
private MasterHouseRepository masterHouseRepository; | ||
|
||
@Autowired | ||
private CacheManager listCacheManager; | ||
|
||
@Test | ||
void shouldRetrieveWizardsAgainstValidHouseId() { | ||
// fetch random house record from datasource | ||
final var house = masterHouseRepository.fetchRandom().orElseThrow(AssertionFailedError::new); | ||
|
||
// create wizard record | ||
final var firstName = RandomString.make(); | ||
final var lastName = RandomString.make(); | ||
final var wizard = new Wizard(); | ||
wizard.setFirstName(firstName); | ||
wizard.setLastName(lastName); | ||
wizard.setGender("Male"); | ||
wizard.setHouseId(house.getId()); | ||
wizardRepository.save(wizard); | ||
|
||
// invoke method under test | ||
final List<WizardDto> retrievedWizards = masterHouseService.retrieveWizardsByHouseId(house.getId()); | ||
|
||
// assert presence of saved wizard in retrieved records and verify datasource interaction | ||
assertThat(retrievedWizards).isNotNull().isNotEmpty(); | ||
assertThat(retrievedWizards).map(WizardDto::getFirstName).contains(firstName); | ||
assertThat(retrievedWizards).map(WizardDto::getLastName).contains(lastName); | ||
verify(wizardRepository, times(1)).findByHouseId(house.getId()); | ||
} | ||
|
||
@Test | ||
void shouldRetrieveWizardRecordsByHouseIdFromCacheAfterInitialDatabaseRetrieval() { | ||
// fetch random house record from datasource | ||
final var house = masterHouseRepository.fetchRandom().orElseThrow(AssertionFailedError::new); | ||
final var houseId = house.getId(); | ||
|
||
// create wizard record | ||
final var firstName = RandomString.make(); | ||
final var lastName = RandomString.make(); | ||
final var wizard = new Wizard(); | ||
wizard.setFirstName(firstName); | ||
wizard.setLastName(lastName); | ||
wizard.setGender("Male"); | ||
wizard.setHouseId(houseId); | ||
wizardRepository.save(wizard); | ||
|
||
// assert cache does not contain wizard records corresponding to house-id | ||
var cachedWizardRecords = listCacheManager.getCache("wizards").get(houseId); | ||
assertThat(cachedWizardRecords).isNull(); | ||
|
||
// invoke method under test and assert that initial retrieval is done from datasource | ||
masterHouseService.retrieveWizardsByHouseId(houseId); | ||
verify(wizardRepository, times(1)).findByHouseId(houseId); | ||
Mockito.clearInvocations(wizardRepository); | ||
|
||
// invoke method under test multiple times to verify subsequent reads are made from cache and datasource is not queried | ||
final var queryTimes = 100; | ||
for (int i = 1; i < queryTimes; i++) { | ||
masterHouseService.retrieveWizardsByHouseId(houseId); | ||
} | ||
verify(wizardRepository, times(0)).findByHouseId(houseId); | ||
} | ||
|
||
@Test | ||
void shouldThrowExceptionForInvalidHouseId() { | ||
// prepare invalid house-id | ||
final var houseId = UUID.randomUUID(); | ||
|
||
// invoke method under test and verify datasource interaction | ||
assertThrows(InvalidHouseIdException.class, () -> masterHouseService.retrieveWizardsByHouseId(houseId)); | ||
verify(wizardRepository, times(1)).findByHouseId(houseId); | ||
} | ||
|
||
@Test | ||
void shouldReturnNonEmptyHouseListPostFlywayMigrationExecution() { | ||
// Retrieve the list of house records saved in the datasource | ||
final var retrievedHouses = masterHouseService.retrieve(); | ||
|
||
// Verify that the list of countries is not empty and flyway migration script is executed | ||
assertThat(retrievedHouses).isNotNull().isNotEmpty().hasSizeGreaterThanOrEqualTo(4); | ||
assertThat(retrievedHouses).map(HouseDto::getId).doesNotContainNull(); | ||
assertThat(retrievedHouses).map(HouseDto::getName).doesNotContainNull(); | ||
} | ||
|
||
@Test | ||
void shouldFetchRandomHouseRecordFromDataSource() { | ||
// invoke method under test | ||
final var retrievedHouse = masterHouseService.retrieveRandom(); | ||
|
||
// assert response attributes | ||
assertThat(retrievedHouse).isNotNull().isInstanceOf(HouseDto.class) | ||
.satisfies(house -> { | ||
assertThat(house.getId()).isNotNull(); | ||
assertThat(house.getName()).isNotNull(); | ||
}); | ||
} | ||
|
||
} |
Oops, something went wrong.