Écriture de tests @SpringBootTest lors de l'utilisation de Spring Shell dans une application

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 {
		//do nothing
	}
	

}

@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";

	/**
	 * The name of the environment property that allows to disable the behavior of this
	 * runner.
	 */
	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.


All Articles