Skip to content

Provide test case for the GRASP "information expert" principle #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import java.math.BigDecimal;
import java.math.RoundingMode;

record Money(BigDecimal amount) {
public record Money(BigDecimal amount) {

Money(BigDecimal amount) {
public static Money ZERO = new Money(BigDecimal.ZERO);

public Money(BigDecimal amount) {
if (amount == null) {
throw new IllegalArgumentException("Amount must not be null");
}
Expand All @@ -27,6 +29,10 @@ public Money subtract(Money other) {
return new Money(this.amount.subtract(other.amount));
}

public Money multiply(BigDecimal multiplier) {
return new Money(this.amount.multiply(multiplier));
}

public static Money of(BigDecimal amount) {
return new Money(amount);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package pl.mperor.lab.java.clean.code.grasp;

/**
* General Responsibility Assignment Software Pattern (1997)
* - OOP design principles.
*/
public interface GRASP {
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class ValueObjectTest {

@Test
void shouldAllowToUseMoneyAsValueObject() {
var money = Money.of(BigDecimal.ZERO);
var money = Money.ZERO;
Assertions.assertEquals(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_EVEN), money.amount());

Assertions.assertThrows(IllegalArgumentException.class, () -> new Money(null));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package pl.mperor.lab.java.clean.code.grasp;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import pl.mperor.lab.java.clean.code.ddd.value.object.Money;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

/**
* 🤓 Information Expert
*
* <p>The principle states that a class should be responsible for behavior
* that is directly related to its data.
*
* This test verifies that:
* <ul>
* <li>{@link Order} calculates its total price.</li>
* <li>{@link Cart} aggregates the total cost of multiple orders.</li>
* </ul>
* Each class encapsulates its own logic, following the principle of expert knowledge.
*/
class InformationExpertTest {

record Cart(List<Order> order) {
Cart(Order... orders) {
this(Arrays.asList(orders));
}

Cart(List<Order> order) {
this.order = List.copyOf(order);
}

Money totalCost() {
return order.stream()
.map(Order::totalPrice)
.reduce(Money.ZERO, Money::add);
}
}

record Order(OrderItem item, int quantity) {
Order {
if (quantity < 1) {
throw new IllegalArgumentException("Quantity must be greater then 0!");
}
}

Money totalPrice() {
return item.price.multiply(BigDecimal.valueOf(quantity));
}
}

record OrderItem(String name, Money price) {}

@Test
void cartShouldFollowInformationExpertPrinciple () {
var pencil = new OrderItem("Pencil", Money.of(BigDecimal.ONE));
var rubber = new OrderItem("Rubber", Money.of(new BigDecimal("1.5")));
var cart = new Cart(
new Order(pencil, 2),
new Order(rubber, 1)
);

Assertions.assertEquals(new Money(new BigDecimal("3.50")), cart.totalCost());
Assertions.assertThrows(IllegalArgumentException.class, () -> new Order(pencil, 0));
}
}