'Java integration test with fake outbound call

I work on a Java project using Spring framework, JUnit and Mockito.

The application is in the middle of a chain with others application, so it exposes inbound ports (e.g. an HTTP API) to be called and uses outbound ports (e.g. web services and database) to call other apps.

I want to write something like an integration test that should pass through the whole java code from the inbound port to the outbound port, but without doing any call to anything that's outside of the project.

Let's take a very-simple-but-very-concrete example :

class diagram

We expose an HTTP endpoint to get customers and we call another app to get them.

  • In the domain : customers are represented by the Customer class.
  • In the externalapp layer : customers are represented by the CustomerModel class.
  • In the rest layer : customers are represented by the CustomerDto class.

Thus :

  • The CustomerSupplierAdapter class gets data from CustomerRepository and does the mapping from CustomerModel to Customer.
  • The CustomerControllerAdapter class does the mapping from Customer to CustomerDto and returns the data.

Now, I want to test my app by calling the CustomerControllerAdapter's getCustomers(), which will call the real service, which will call the real supplier, which will call a fake repository.

I wrote the following code :

@ExtendWith(SpringExtension.class)
class CustomerIntegrationTest {

    @Mock
    private CustomerRepository repository;

    @InjectMocks
    private CustomerControllerAdapter controller;

    @BeforeAll
    void setupAll() {
        CustomerOutboundPort customerOutboundPort = new CustomerSupplierAdapter(repository);
        CustomerInboundPort customerInboundPort = new CustomerService(customerOutboundPort);
        controller = new CustomerControllerAdapter(customerInboundPort);
    }

    @Test
    void bulkQuery() {
        // Given
        CustomerModel model = new CustomerModel();
        model.setName("Arya Stark");
        doReturn(List.of(model)).when(repository).getCustomers();

        // When
        List<CustomerDto> dtos = controller.getCustomers();

        // Then
        assertThat(dtos).hasSize(1);
        assertThat(dtos.get(0).getName()).isEqualTo("Arya Stark");
    }
    
}

But in this code, I do the "constructor's wiring" by myself in the setupAll() instead of relying on Spring dependency injection. It is not a viable solution because it would be very hard to maintain in real-life context (controller may have multiple services, service may have multiple suppliers, etc).

Actually, I would like to have something like an annotation to set on a CustomerRepository instance to programmatically overload dependency injection. Like : "Hey Spring, if any @Service class needs a CustomerRepository then you should use this fake one instead of the usual concrete implementation" without having to do the wiring by myself.

Is there any way to achieve that using Spring, JUnit, Mockito or anything else ?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source