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();
}
}