package com.bookshop.behavioral.strategy;
import static org.junit.jupiter.api.Assertions.assertEquals;
import com.bookshop.domain.Book;
import com.bookshop.domain.Customer;
import java.math.BigDecimal;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@DisplayName("Strategy -- swapping pricing rules without touching the calculator")
class PriceCalculatorTest {
private final List<Book> basket = List.of(
new Book("978-0134757599", "Refactoring", "Martin Fowler", new BigDecimal("47.99")),
new Book("978-0134685991", "Effective Java", "Joshua Bloch", new BigDecimal("39.99")));
private final Customer loyalAlice = new Customer("c-1", "Alice", "alice@example.com", 4);
private final Customer newBob = new Customer("c-2", "Bob", "bob@example.com", 0);
@Test
@DisplayName("the same calculator prices the same basket differently per strategy")
void strategiesAreInterchangeable() {
BigDecimal subtotal = new BigDecimal("87.98");
assertEquals(subtotal,
new PriceCalculator(Discounts.none()).totalFor(basket, newBob));
assertEquals(new BigDecimal("80.94"),
new PriceCalculator(Discounts.loyalty()).totalFor(basket, loyalAlice));
assertEquals(new BigDecimal("74.78"),
new PriceCalculator(Discounts.bulkOrder()).totalFor(basket, newBob));
}
@Test
@DisplayName("each strategy is a tiny unit, testable on its own")
void strategiesTestableInIsolation() {
assertEquals(new BigDecimal("8.00"),
Discounts.loyalty().discountFor(new BigDecimal("100.00"), loyalAlice));
assertEquals(BigDecimal.ZERO,
Discounts.bulkOrder().discountFor(new BigDecimal("49.99"), newBob));
}
@Test
@DisplayName("a one-off promotion is just a lambda -- no new class ceremony")
void oneOffStrategyAsLambda() {
DiscountStrategy flatFiver = (subtotal, customer) -> new BigDecimal("5.00");
BigDecimal total = new PriceCalculator(flatFiver).totalFor(basket, newBob);
assertEquals(new BigDecimal("82.98"), total);
}
}