Parfois, dans les applications, il est utile d'avoir une console pour gérer l'application directement à partir du serveur. L'une des solutions extrêmement pratiques à ce problème est Spring Shell.
Les tests sont également une très bonne pratique (j'espère que vous les avez) et, parfois, ils sont écrits avec l'annotation @SpringBootTest. Cependant, si vous branchez Spring Shell et essayez d'exécuter un tel test, alors ... votre test se bloquera simplement en prévision d'une commande de la console.
Nous partons donc à la recherche d'une solution.Google
Après une courte recherche sur GitHub, nous trouvons un problème similaire .
Pour tester le shell, l'auteur suggère de remplacer le bac par le type ApplicationRunner, qui attend une commande de la console. Voici la solution pour accéder et tester les commandes elles-mêmes définies dans @ShellComponent.
@Component
public class CliAppRunner implements ApplicationRunner {
public CliAppRunner() {
}
@Override
public void run(ApplicationArguments args) throws Exception {
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes =CliConfig.class)
public class ShellCommandIntegrationTest {
@Autowired
private Shell shell;
@Test
public void runTest(){
Object result=shell.evaluate(new Input(){
@Override
public String rawText() {
return "add 1 3";
}
});
DefaultResultHandler resulthandler=new DefaultResultHandler();
resulthandler.handleResult(result);
}
}
Malheureusement, les tests avec cette solution attendent toujours l'équipe.Il est temps de regarder sous le capot!
Après un léger débogage, nous trouvons le code suivant dans la classe SpringApplication:
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
En d'autres termes, Spring Boot ajoute simplement notre bac avec ApplicationRunner personnalisé à ceux déjà définis et les lance tous.Il semblerait que la solution soit simple - redéfinissez le bac! Il est temps d'entrer dans la source Spring Shell.
Redéfinir le haricot
Il devient rapidement clair que la classe JLineShellAutoConfiguration est responsable de la création des coureurs, en particulier nous sommes intéressés par le bean scriptApplicationRunner, ce qui empêche notre test de démarrer.
, ( spring.main.allow-bean-definition-overriding=true Spring 2.+):
@TestConfiguration
static class Runner {
@Bean
public ApplicationRunner scriptApplicationRunner(){
return new CliAppRunner();
}
}
, . JLineShellAutoConfiguration Runner scriptApplicationRunner. ( — - — , ?).
, , JLineShellAutoConfiguration:
@Bean
@ConditionalOnProperty(prefix = SPRING_SHELL_SCRIPT, value = ScriptShellApplicationRunner.ENABLED, havingValue = "true", matchIfMissing = true)
public ApplicationRunner scriptApplicationRunner(Parser parser, ConfigurableEnvironment environment) {
return new ScriptShellApplicationRunner(parser, shell, environment);
}
, — property, . application.properties:
spring.shell.script.enabled=false
. . .
ScriptShellApplicationRunner , property. :
public static final String SPRING_SHELL_SCRIPT = "spring.shell.script";
public static final String ENABLED = "spring.shell.script";
public static final String SPRING_SHELL_SCRIPT_ENABLED = SPRING_SHELL_SCRIPT + "." + ENABLED;
Wow, tout semble clair maintenant - retournez à application.properties et écrivez:
spring.shell.script.spring.shell.script=false
Croiser les doigts. Exécutez le test. Travaux.
L'affaire est résolue, merci de votre attention.