'How to test a Spring CommandLineRunner while I am mocking the connection to an external resources?

I want to test the following class, that is a spring boot with CommandLineRunner, if it receives the flag compaction.manually.triggered = true for specific TaskMode. I suppose that I need to instantiate the whole Spring application runner during the test (based on this answer). However, I don't want to connect to external resources (was in my case). So I think I need to mock it as well.

@Component
public class MyRunner implements CommandLineRunner {
    private final MyTask myTask;
    private final CompactionMode mode;
    private final boolean manuallyTriggered;

    @Autowired
    public MyRunner(
        MyTask myTask,
        @Value("${task.mode}") TaskMode mode,
        @Value("#{new Boolean('${compaction.manually.triggered:false}')}") boolean manuallyTriggered
    ) {
        Preconditions.checkNotNull(mode, "Compaction mode was not specified correctly");
        this.mode = mode;
        this.manuallyTriggered = manuallyTriggered;
        this.myTask = myTask;
    }

    @Override
    public void run(final String... args) {
        try {
            Preconditions.checkNotNull(mode, "Compaction mode was not specified correctly");
            LOG.info(
                "Task reporting compactor in {} mode started. The task was triggered {}.",
                mode,
                manuallyTriggered ? "manually" : "by the conJob schedule"
            );
            switch (mode) {
                case KPI, ANALYTICS, ANALYTICS_AGG -> {
                    checkManuallyTriggered(mode);
                    myTask.executeTask();
                }
                default -> throw new UnsupportedOperationException("myTask mode " + mode + " is not supported.");
            }
            System.exit(0);
        } catch (Exception ex) {
            LOG.error("Failure during mytask in {} mode", mode, ex);
            System.exit(-1);
        }
    }
    private void checkManuallyTriggered(CompactionMode mode) {
        if (!manuallyTriggered) {
            throw new UnsupportedOperationException(
                "Reporting compactor mode " + mode.name() + " is supported only using the " + "parameter --compaction.manually.triggered=true.");
        }
    }
}

I wrote the test below and my commandLineRunner is Null when I use @ExtendWith(MockitoExtension.class). I understand that I cannot use @ExtendWith(MockitoExtension.class) and want that Spring initializes my context. So I tried to switch to @SpringBootTest. Then spring initializes my context but it tries to connect to AWS. So, I don't know to mock the connection to AWS while using @SpringBootTest to initialize the spring context during test.

// @SpringBootTest // ENABLE THIS TO TEST THE CommandLineRunner
@ExtendWith(MockitoExtension.class) // ENABLE THIS TO MOCK THE SERVICES CONNECTION TO AWS
class ReportingCompactorRunnerTest {

    AthenaProperties athenaProperties = new AthenaProperties(
        "com.simba.athena.jdbc42.Driver",
        "eu-central-1",
        "database",
        "test_reports"
    );
    private AthenaDirectConnection athenaDirectConnection = mock(AthenaDirectConnection.class, Mockito.RETURNS_DEEP_STUBS);
    private MockSettings mockSettings = withSettings().useConstructor(athenaDirectConnection, athenaProperties);
    private AthenaImportDDLService athenaImportDDLService = mock(AthenaImportDDLService.class, mockSettings);
    @Mock
    private MyTask myTask;
    @SpyBean // using this annotation to spy the arguments on the CommandLineRunner
    private ReportingCompactorRunner commandLineRunner;

    @DynamicPropertySource
    static void containerProperties(DynamicPropertyRegistry registry) {
        registry.add("compaction.mode", () -> "KPI");
        registry.add("compaction.manually.triggered", () -> "false");
    }
    @Test
    void analyticsCleanupIsTriggeredOnlyManually() throws Exception {
        doNothing().when(myTask).createViewsIfNotExist(); // a call inside the task that I don't want to execute

        // commandLineRunner IS NULL WHEN I USE MOCKITO
        RuntimeException thrown = assertThrows(
            RuntimeException.class,
            () -> commandLineRunner.run()
        );

        // assertTrue(thrown.getMessage().contains("Reporting compactor mode ANALYTICS_CLEANUP is supported only
        // using the parameter --compaction.manually.triggered=true."));
        assertTrue(thrown.getMessage().contains("null"));
        verify(athenaReportCompactionTask, times(1)).executeTask();
    }
}


Sources

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

Source: Stack Overflow

Solution Source