#StackBounty: #java #spring #spring-boot #mocking #integration-testing Spring Boot Integration Testing – Mocking @Service before Applic…

Bounty: 50

I have to create a integration test for a microservice X which downloads, processes and importing csv files from external sftp servers. The whole process is started by a spring boot scheduler task which starts a spring batch job for processing and importing the data. The import process is done by the spring batch writer, which is a restTemplate Repository (so it calls post requests to another microservice Y).

I already managed to mock the sftp server, putting a test file on it and the current integration test is downloading the file. (https://github.com/stefanbirkner/fake-sftp-server-rule/)

My problem is, that the task will be scheduled immediately when the application context starts so there is no trigger like a api call. To get the whole integration test working i have to mock the part where the external microservice Y is called through a restTemplate call. This repository is called in the spring batch writer and this repository is created by a repositoryFactory which is a @Service. The repositoryFactory is injected in the spring batch configuration class.

I already tried to use the @MockBean annotation in the test class as well as in a separate test configuration where i am mocking the create() function of the factory to deliver a repository mock. But at some point it does not work and it delivers still the original object which leads to interupt the import job.

I also tried to use the WireMock library, but also in this case it does not catched any api calls and at some point leads to interrupt the sftp socket. (?)

I hope someone could help me out.

The current test:

@NoArgsConstructor
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(classes = {JsonHalConfig.class})
@TestPropertySource(locations = "classpath:application-test.properties")
@TestMethodOrder(MethodOrderer.MethodName.class)
public class ImportIT {

    @ClassRule
    public static final FakeSftpServerRule sftpServer = new FakeSftpServerRule();
    private static final String PASSWORD = "password";
    private static final String USER = "username";
    private static final int PORT = 14022;

    @BeforeClass
    public static void beforeClass() throws IOException {
        URL resource = getTestResource();
        if (resource != null) {
            sftpServer.setPort(PORT).addUser(USER, PASSWORD);
            sftpServer.createDirectories("/home/username/it-space/IMPORT", "/home/username/it-space/EXPORT");
            sftpServer.putFile("/home/username/it-space/IMPORT/INBOX/testFile.csv",
                    resource.openStream());
        } else {
            throw new IOException("Failed to get test resources");
        }
    }

    private static URL getTestResource() {
        return ImportIT.class.getClassLoader().getResource("testFile.csv");
    }

    @Test
    public void test_A_() throws IOException, RepositoryException {
        assertTrue(true);
    }
}

I tried following configuration classes

(included in @ContextConfiguration)

@Configuration/@TestConfiguration
public class RepositoryTestConfig {
    @Bean
    @Primary
    public IRepositoryFactory repositoryFactory() {
        IRepositoryFactory repositoryFactory = mock(IRepositoryFactory.class);
        IRepository repository = mock(IRepository.class);
        when(repositoryFactory.create(anyString())).thenReturn(repository);
        return repositoryFactory;
    }
}

(as static class in the test class)

    @TestConfiguration/@Configuration
    public static class RepositoryTestConfig {
        @MockBean
        private IRepositoryFactory repositoryFactory;

        @PostConstruct
        public void initMock(){
            IRepository repository = mock(IRepository.class);
            Mockito.when(repositoryFactory.create(anyString())).thenReturn(
                    repository
            );
        }
    }

UPDATE 27.08.2021
I have a RestConfig @Component where a new RestTemplateBuilder is created. I tried to @MockBean this component to deliver a RestTemplateBuilder Mock and injected a MockRestServiceServer object to catch outgoing api calls. But unfortunately it does not work as aspected. Am i missing something? I also tried to create a "TestRestController" to trigger the scheduling of the task but it never delivers the mock…


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.