Tests: add 6 corner-scenario tests (Specification family, JpaSort.unsafe, Money value object) - 13 total, all green

This commit is contained in:
2026-07-25 08:20:29 +00:00
parent 382e31cc37
commit 51d876d1a7

View File

@@ -2,6 +2,8 @@ package com.ankurm.sdjpa4demo;
import com.ankurm.sdjpa4demo.domain.Author; import com.ankurm.sdjpa4demo.domain.Author;
import com.ankurm.sdjpa4demo.domain.Book; import com.ankurm.sdjpa4demo.domain.Book;
import com.ankurm.sdjpa4demo.domain.BookSummary;
import com.ankurm.sdjpa4demo.domain.Money;
import com.ankurm.sdjpa4demo.repo.AuthorRepository; import com.ankurm.sdjpa4demo.repo.AuthorRepository;
import com.ankurm.sdjpa4demo.repo.BookRepository; import com.ankurm.sdjpa4demo.repo.BookRepository;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -11,11 +13,15 @@ import org.springframework.test.context.ActiveProfiles;
import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.JpaSort;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
import static com.ankurm.sdjpa4demo.repo.AuthorSpecifications.byCountryDelete;
import static com.ankurm.sdjpa4demo.repo.AuthorSpecifications.hasCountry;
import static com.ankurm.sdjpa4demo.repo.AuthorSpecifications.relabelCountry;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest @SpringBootTest
@@ -29,8 +35,8 @@ class MigrationBehaviorTests {
private void seed() { private void seed() {
Author a1 = authors.save(new Author("Joshua Bloch", "US")); Author a1 = authors.save(new Author("Joshua Bloch", "US"));
authors.save(new Author("Anonymous", null)); authors.save(new Author("Anonymous", null));
books.save(new Book("Effective Java", new BigDecimal("45.00"), a1)); books.save(new Book("Effective Java", new Money(new BigDecimal("45.00"), "USD"), a1));
books.save(new Book("Refactoring", new BigDecimal("45.00"), a1)); books.save(new Book("Refactoring", new Money(new BigDecimal("45.00"), "USD"), a1));
} }
@Test @Test
@@ -70,7 +76,7 @@ class MigrationBehaviorTests {
void nonUniqueSingleResultThrows() { void nonUniqueSingleResultThrows() {
seed(); seed();
assertThrows(IncorrectResultSizeDataAccessException.class, assertThrows(IncorrectResultSizeDataAccessException.class,
() -> books.findByPrice(new BigDecimal("45.00"))); () -> books.findByPriceAmount(new BigDecimal("45.00")));
} }
@Test @Test
@@ -78,4 +84,74 @@ class MigrationBehaviorTests {
Author a = authors.save(new Author("Erich Gamma", "CH")); Author a = authors.save(new Author("Erich Gamma", "CH"));
assertEquals("Erich_Gamma:CH", authors.badgeFor(a.getId())); assertEquals("Erich_Gamma:CH", authors.badgeFor(a.getId()));
} }
// --- Corner scenarios: refined Specification API (DeleteSpecification / UpdateSpecification / PredicateSpecification) ---
@Test
void predicateSpecificationReusedAcrossReadAndDelete() {
authors.save(new Author("Grady Booch", "US"));
authors.save(new Author("Robert Martin", "US"));
authors.save(new Author("Martin Fowler", "UK"));
assertEquals(2, authors.findAll(hasCountry("US")).size());
long removed = authors.delete(hasCountry("US"));
assertEquals(2, removed);
assertTrue(authors.findAll(hasCountry("US")).isEmpty());
}
@Test
void deleteSpecificationBulkDelete() {
authors.save(new Author("Kent Beck", "DE"));
authors.save(new Author("Erich Gamma", "CH"));
long removed = authors.delete(byCountryDelete("DE"));
assertEquals(1, removed);
assertTrue(authors.findByCountry("DE") == null);
}
@Test
void updateSpecificationBulkUpdate() {
authors.save(new Author("Martin Fowler", "UK"));
authors.save(new Author("Sam Newman", "UK"));
long updated = authors.update(relabelCountry("UK", "GB"));
assertEquals(2, updated);
assertEquals(2, authors.findAll(hasCountry("GB")).size());
assertTrue(authors.findAll(hasCountry("UK")).isEmpty());
}
@Test
void jpaSortUnsafeCaseExpressionOrdersResults() {
authors.save(new Author("Alpha Author", "DE"));
authors.save(new Author("Beta Author", "US"));
Sort usFirst = JpaSort.unsafe(Sort.Direction.ASC, "CASE WHEN country = 'US' THEN 0 ELSE 1 END");
List<Author> ordered = authors.findByNameStartingWith("", usFirst);
assertEquals("US", ordered.get(0).getCountry());
}
// --- Corner scenarios: Money embeddable value object ---
@Test
void embeddedValueObjectPathTraversalWorks() {
seed();
List<Book> found = books.findByPriceAmountGreaterThanEqual(new BigDecimal("45.00"));
assertEquals(2, found.size());
}
@Test
void recordProjectionPopulatesFromEmbeddedPath() {
Author a = authors.save(new Author("Kathy Sierra", "US"));
books.save(new Book("Head First Java", new Money(new BigDecimal("39.99"), "USD"), a));
List<BookSummary> summaries = books.findByPriceAmountLessThanEqual(new BigDecimal("40.00"));
assertEquals(1, summaries.size());
assertEquals("Head First Java", summaries.get(0).title());
assertEquals(new BigDecimal("39.99"), summaries.get(0).amount());
}
} }