Skip to main content
Advertisement

12.2 Order/List CRUD and Business Logic Unit Testing

Based on the knowledge gained, you will learn how to integrate a simple ordering system and verify that your code works correctly.

1. Requirement Definition

  • Users can order products (including basic inventory check logic).
  • Users can view a list of orders.
  • Canceling an order should restore inventory.

2. Domain Model Design (JPA)

@Entity
@Table(name = "orders")
public class Order {
@Id @GeneratedValue
private Long id;

private String itemName;
private int orderPrice;
private int count;

@Enumerated(EnumType.STRING)
private OrderStatus status; // ORDER, CANCEL

// Includes creation methods and business logic (restoring stock on cancellation) - Domain-Driven Design
}

3. Unit Testing

In a Spring Boot environment, you can use JUnit 5 and Mockito to quickly test logic in specific layers.

Service Layer Testing Example

@ExtendWith(MockitoExtension.class)
class OrderServiceTest {

@Mock OrderRepository orderRepository;
@InjectMocks OrderService orderService;

@Test
void order_success() {
// given
OrderDto dto = new OrderDto("Laptop", 1000, 2);

// when
Long orderId = orderService.createOrder(dto);

// then
verify(orderRepository).save(any(Order.class));
}
}

4. Integration Testing

Use the @SpringBootTest annotation to load actual beans into the container and conduct tests that include database connections.

@SpringBootTest
@Transactional
class OrderFlowIntegrationTest {
@Autowired OrderService orderService;

@Test
void full_order_flow_test() {
// ... Scenario testing using a real database
}
}

5. Transaction Management and Data Integrity

One of the most critical aspects of a practical mini project is Transaction Management. You must declare @Transactional on service methods that manipulate multiple entities to ensure data integrity.

@Service
@RequiredArgsConstructor
public class OrderService {
private final OrderRepository orderRepository;
private final ProductRepository productRepository;

@Transactional // Encapsulates the entire method into a single transaction
public Long createOrder(OrderDto dto) {
// 1. Deduct product stock (Throws exception on failure)
Product product = productRepository.findByName(dto.getItemName());
product.removeStock(dto.getCount());

// 2. Create and save order
Order order = Order.createOrder(product, dto.getCount());
orderRepository.save(order);

return order.getId();
}
}
  • Guarantees Atomicity: Prevents situations where stock is deducted but the order record fail to save.
  • Dirty Checking: When using JPA, changes to entities are automatically reflected in the DB upon transaction completion without explicit save() calls.

🎯 Key Points

  • In real-world projects, it is better to place business logic inside domain entities.
  • Unit tests remove external dependencies and quickly verify the logic itself.
  • Integration tests provide final confirmation that the overall flow of the system is correct.
Advertisement