Files
awesome-copilot/skills/spring-boot-testing/references/instancio.md
Kartik Dhiman e4fc57f204 feat: add spring-boot-testing skill for Spring Boot 4.0 (#1085)
- Introduced MockMvcTester for AssertJ-style assertions in Spring MVC testing.
- Added @RestClientTest for testing REST clients with MockRestServiceServer.
- Implemented RestTestClient as a modern alternative to TestRestTemplate.
- Documented migration steps from Spring Boot 3.x to 4.0, including dependency and annotation changes.
- Created an overview of test slices to guide testing strategies.
- Included Testcontainers setup for JDBC testing with PostgreSQL and MySQL.
- Enhanced @WebMvcTest documentation with examples for various HTTP methods and validation.
2026-03-20 10:24:37 +11:00

4.8 KiB

Instancio

Generate complex test objects automatically. Use when entities/DTOs have 3+ properties.

When to Use

  • Objects with 3 or more properties
  • Setting up test data for repositories
  • Creating DTOs for controller tests
  • Avoiding repetitive builder/setter calls

Dependency

<dependency>
  <groupId>org.instancio</groupId>
  <artifactId>instancio-junit</artifactId>
  <version>5.5.1</version>
  <scope>test</scope>
</dependency>

Basic Usage

Simple Object

final var order = Instancio.create(Order.class);
// All fields populated with random data

List of Objects

final var orders = Instancio.ofList(Order.class).size(5).create();
// 5 orders with random data

Customizing Values

Set Specific Fields

final var order = Instancio.of(Order.class)
  .set(field(Order::getStatus), "PENDING")
  .set(field(Order::getTotal), new BigDecimal("99.99"))
  .create();

Supply Generated Values

final var order = Instancio.of(Order.class)
  .supply(field(Order::getEmail), () -> "user" + UUID.randomUUID() + "@test.com")
  .create();

Ignore Fields

final var order = Instancio.of(Order.class)
  .ignore(field(Order::getId)) // Let DB generate
  .create();

Complex Objects

Nested Objects

final var order = Instancio.of(Order.class)
  .set(field(Order::getCustomer), Instancio.create(Customer.class))
  .set(field(Order::getItems), Instancio.ofList(OrderItem.class).size(3).create())
  .create();

All Fields Random

// When you need fully random but valid data
final var randomOrder = Instancio.create(Order.class);
// Customer, items, addresses - all populated

Spring Boot Integration

Repository Test Setup

@DataJpaTest
@AutoConfigureTestDatabase
@Testcontainers
class OrderRepositoryTest {
  
  @Container
  @ServiceConnection
  static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:18");
  
  @Autowired
  private OrderRepository orderRepository;
  
  @Test
  void shouldFindOrdersByStatus() {
    // Given: Create 10 random orders with PENDING status
    final var orders = Instancio.ofList(Order.class)
      .size(10)
      .set(field(Order::getStatus), "PENDING")
      .create();
    
    orderRepository.saveAll(orders);
    
    // When
    final var found = orderRepository.findByStatus("PENDING");
    
    // Then
    assertThat(found).hasSize(10);
  }
}

Controller Test Setup

@WebMvcTest(OrderController.class)
class OrderControllerTest {
  
  @Autowired
  private MockMvcTester mvc;
  
  @MockitoBean
  private OrderService orderService;
  
  @Test
  void shouldReturnOrder() {
    // Given: Random order with specific ID
    Order order = Instancio.of(Order.class)
      .set(field(Order::getId), 1L)
      .create();
    
    given(orderService.findById(1L)).willReturn(order);
    
    // When/Then
    assertThat(mvc.get().uri("/orders/1"))
      .hasStatus(HttpStatus.OK)
      .bodyJson()
      .convertTo(OrderResponse.class)
      .satisfies(response -> {
        assertThat(response.getId()).isEqualTo(1L);
      });
  }
}

Patterns

Builder Pattern Alternative

// Instead of:
Order order = Order.builder()
  .id(1L)
  .status("PENDING")
  .customer(Customer.builder().name("John").build())
  .items(List.of(
    OrderItem.builder().product("A").price(10).build(),
    OrderItem.builder().product("B").price(20).build()
  ))
  .build();

// Use:
Order order = Instancio.of(Order.class)
  .set(field(Order::getId), 1L)
  .set(field(Order::getStatus), "PENDING")
  .create();
// Customer and items auto-generated

Seeded Data

// Consistent "random" data for reproducible tests
Order order = Instancio.of(Order.class)
  .withSeed(12345L)
  .create();
// Same data every test run with seed 12345

Common Patterns

Email Generation

String email = Instancio.gen().net().email();

Date Generation

LocalDateTime createdAt = Instancio.gen().temporal()
  .localDateTime()
  .past()
  .create();

String Patterns

String phone = Instancio.gen().text().pattern("+1-###-###-####");

Comparison

Approach Lines of Code Maintainability
Manual setters 10-20 Low
Builder pattern 5-10 Medium
Instancio 2-5 High

Best Practices

  1. Use for 3+ property objects - Not worth it for simple objects
  2. Set only what's relevant - Let Instancio fill the rest
  3. Use with Testcontainers - Great for database seeding
  4. Set IDs explicitly - When testing specific scenarios
  5. Ignore auto-generated fields - Like createdAt, updatedAt