← Back to list

Instancio: A New Way to Create Test Data

Generated by DALL-E

Cem Dırman · 2024-06-12 21:27 · 52 claps · 2.6 min read
#spring-boot #instancio #unit-testing #java #tdd
Open on Medium ↗
Wiki topics: MM · Multimodal & Generative Media

Instancio: A New Way to Create Test Data

Generated by DALL-E

Generated by DALL-E

When writing unit tests, we often use mock data because our goal is to verify that a specific method performs its task as expected.

Generating fake data can sometimes be a tedious process. Instancio solves this problem precisely by producing fake data according to a model we provide.

Instancio

Instancio leverages data types while generating data. However, with this library, our goal is not just to generate fake data, but also to ensure the content of the data is meaningful.

In most cases, when writing unit tests, our objective is to generate data suitable for the test methods. Otherwise, we won’t be able to perform the desired test scenario.

Here are some basic commands to illustrate the usage:

Person person = Instancio.create(Person.class);

Person personWithoutAgeAndAddress = Instancio.of(Person.class)
    .ignore(field(Person::getAddress))
    .create();

List<Person> list = Instancio.createList(Person.class);

List<Person> list = Instancio.ofList(Person.class).size(10).create();

Person person = Instancio.createBlank(Person.class);

// Output:
// Person[name=null, address=Address[street=null, city=null, country=null]]

Person person = Instancio.ofBlank(Person.class)
    .set(field(Address::getCountry), "Canada")
    .create();

// Output:
// Person[name=null, address=Address[street=null, city=null, country=Canada]ja

Adding Instancio to Your Project;

For JUnit 5, the following dependency is sufficient:

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

For JUnit 4, use the following:

<dependency>
    <groupId>org.instancio</groupId>
    <artifactId>instancio-core</artifactId>
    <version>4.7.0</version>
    <scope>test</scope>
</dependency>

Writing Tests for a Controller

Let’s try to write tests for the following controller:

@AllArgsConstructor
@RestController
@RequestMapping("/api/v1/customers")
public class CustomerController {

    private final CustomerService customerService;

    @PostMapping
    public void save(@RequestBody CustomerSaveRequest request) {
        customerService.save(request);
    }

    @GetMapping
    public List<Customer> getAll() {
        return customerService.getCustomerList();
    }
}
import com.fasterxml.jackson.databind.ObjectMapper;
import com.patika.kitapyurdumcustomerservice.dto.request.CustomerSaveRequest;
import com.patika.kitapyurdumcustomerservice.service.CustomerService;
import jakarta.ws.rs.core.MediaType;
import org.instancio.Instancio;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;

import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@WebMvcTest(CustomerController.class)
class CustomerControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private CustomerService customerService;

    @Test
    void save() throws Exception {
        ObjectMapper mapper = new ObjectMapper();

        String body = mapper.writeValueAsString(Instancio.create(CustomerSaveRequest.class));

        mockMvc.perform(post("/api/v1/customers")
                        .content(body)
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk());

        verify(customerService, times(1)).save(Mockito.any(CustomerSaveRequest.class));
    }

    @Test
    void getAll() throws Exception {
        mockMvc.perform(get("/api/v1/customers")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk());

        verify(customerService, times(1)).getCustomerList();
    }
}

Writing Tests for a Service Class

Let’s try to write tests for the following service class:

@Service
@RequiredArgsConstructor
@Slf4j
public class CustomerService {

    private final CustomerRepository customerRepository; 

    public void save(CustomerSaveRequest request) {
        Optional<Customer> foundCustomer = customerRepository.findByEmail(request.getEmail());

        if (foundCustomer.isPresent()) {
            log.error(ExceptionMessages.EMAIL_ALREADY_EXIST);
            throw new KitapYurdumException(ExceptionMessages.EMAIL_ALREADY_EXIST);
        }

        Customer customer = CustomerConverter.toCustomer(request);

        customerRepository.save(customer);

        log.info("customer created. {}", customer.getEmail());
    }
}

Creating test data can often be laborious and boring. If we need specific data, Instancio provides a solution for this as well.

package com.patika.kitapyurdumcustomerservice.service;

import com.patika.kitapyurdumcustomerservice.dto.request.CustomerSaveRequest;
import com.patika.kitapyurdumcustomerservice.exception.ExceptionMessages;
import com.patika.kitapyurdumcustomerservice.exception.KitapYurdumException;
import com.patika.kitapyurdumcustomerservice.model.AccountType;
import com.patika.kitapyurdumcustomerservice.model.Customer;
import com.patika.kitapyurdumcustomerservice.repository.CustomerRepository;
import org.instancio.Instancio;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;
import static org.instancio.Select.field;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class CustomerServiceTest {

    @InjectMocks
    private CustomerService customerService;

    @Mock
    private CustomerRepository customerRepository;

    @Test
    void shouldThrowException_whenUserAlreadyExist() {
        String email = "bilisimio@gmail.com";

        //given
        CustomerSaveRequest request = Instancio.of(CustomerSaveRequest.class)
                .set(field(CustomerSaveRequest::getEmail), email)
                .set(field(CustomerSaveRequest::getName), "bilisimio")
                .create();

        Mockito.when(customerRepository.findByEmail(email))
                .thenReturn(Optional.of(Instancio.of(Customer.class)
                        .set(field(Customer::getEmail), email)
                        .set(field(Customer::getIsActive), false)
                        .set(field(Customer::getAccountType), AccountType.PLATINUM)
                        .create()));

        //when
        KitapYurdumException exception = assertThrows(KitapYurdumException.class, () -> customerService.save(request));

        //then
        assertThat(exception).hasMessage(ExceptionMessages.EMAIL_ALREADY_EXIST);
        verifyNoMoreInteractions(customerRepository);
    }
}

Additional Features

supply Method

With the supply method, we can assign the desired value according to the data type provided.

CustomerSaveRequest request = Instancio.of(CustomerSaveRequest.class)
                .set(field(CustomerSaveRequest::getEmail), email)
                .set(field(CustomerSaveRequest::getName), "bilisimio")
                .supply(all(LocalDate.class), () -> LocalDate.now()) // Assigning the desired value to all LocalDate fields
                .create();

withNullable Method

If some variables need to be null according to the scenario, we can use the withNullable method.

CustomerSaveRequest request = Instancio.of(CustomerSaveRequest.class)
                .set(field(CustomerSaveRequest::getEmail), email)
                .set(field(CustomerSaveRequest::getName), "bilisimio")
                .supply(all(LocalDate.class), () -> LocalDate.now()) // Assigning the desired value to all LocalDate fields
                .withNullable(field(CustomerSaveRequest::getSurname))
                .withNullable(field(CustomerSaveRequest::getProvince))
                .create();

I’ve tried to exemplify the methods I commonly use. For more, you can refer to Instancio’s official documentation.

If my content helped you or made you smile, feel free to return the favor with a coffee! ☕🚀

buy me a coffee

I hope you find this helpful.


메타데이터
post_id
bb56b20c78c7
slug
instancio-a-new-way-to-create-test-data-bb56b20c78c7
url
https://medium.com/@cemdrman/instancio-a-new-way-to-create-test-data-bb56b20c78c7
canonical_url
https://medium.com/@cemdrman/instancio-a-new-way-to-create-test-data-bb56b20c78c7
author_url
https://medium.com/@cemdrman
status
ok
fetched_at
2026-08-01 02:30:26