Escribir pruebas @SpringBootTest cuando se usa Spring Shell en una aplicación

A veces en las aplicaciones es útil tener una consola para administrar la aplicación directamente desde el servidor. Una de las soluciones extremadamente convenientes para este problema es Spring Shell.


Las pruebas también son una muy buena práctica (espero que las tenga) y, a veces, se escriben con la anotación @SpringBootTest. Sin embargo, si conecta Spring Shell e intenta ejecutar tal prueba, entonces ... su prueba simplemente se congelará en anticipación de un comando de la consola.


Entonces, vamos en busca de una solución.

Google


Después de una breve búsqueda en GitHub, encontramos un problema similar .


Para probar el shell, el autor sugiere reemplazar el bin con el tipo ApplicationRunner, que espera un comando de la consola. Aquí está la solución para acceder y probar los comandos definidos en @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);
		
		
	}
	
	
}

Desafortunadamente, las pruebas con esta solución aún se quedan esperando al equipo.

¡Es hora de mirar debajo del capó!


Después de una depuración ligera, encontramos el siguiente código en la clase 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 otras palabras, Spring Boot simplemente agrega nuestro contenedor con ApplicationRunner personalizado a los ya definidos y los lanza a todos.

Parece que la solución es simple: redefinir el contenedor. Es hora de entrar en la fuente Spring Shell.


Redefinir frijol


Rápidamente queda claro que la clase JLineShellAutoConfiguration es responsable de crear los corredores, específicamente estamos interesados ​​en el bean scriptApplicationRunner, que impide que comience nuestra prueba.


, ( 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, todo parece claro ahora: regrese a application.properties y escriba:


spring.shell.script.spring.shell.script=false 

Cruza tus dedos. Ejecute la prueba Trabajos.


El caso está resuelto, gracias por su atención.


All Articles