Gravando testes @SpringBootTest ao usar o Spring Shell em um aplicativo

Às vezes, nos aplicativos, é útil ter um console para gerenciar o aplicativo diretamente do servidor. Uma das soluções extremamente convenientes para esse problema é o Spring Shell.


Os testes também são uma prática muito boa (espero que você os tenha) e, às vezes, são gravados com a anotação @SpringBootTest. No entanto, se você conectar o Spring Shell e tentar executar esse teste, ... seu teste simplesmente congelará em antecipação a um comando do console.


Então, nós estamos indo em busca de uma solução.

Google


Após uma breve pesquisa no GitHub, encontramos um problema semelhante .


Para testar o shell, o autor sugere substituir o compartimento pelo tipo ApplicationRunner, que espera um comando do console. Aqui está a solução para acessar e testar os próprios comandos definidos em @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);
		
		
	}
	
	
}

Infelizmente, os testes com esta solução ainda estão pendentes aguardando a equipe.

É hora de olhar para baixo do capô!


Após uma depuração leve, encontramos o seguinte código na 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);
			}
		}
	}

Em outras palavras, o Spring Boot simplesmente adiciona nossa lixeira com ApplicationRunner personalizado às já definidas e lança todas elas.

Parece que a solução é simples - redefina a lixeira! Hora de entrar na fonte do Spring Shell.


Redefinir feijão


Torna-se rapidamente claro que a classe JLineShellAutoConfiguration é responsável por criar os corredores, especificamente estamos interessados ​​no bean scriptApplicationRunner, que impede o início do teste.


, ( 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;

Uau, tudo parece claro agora - volte para application.properties e escreva:


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

Cruze seus dedos. Execute o teste. Trabalho.


O caso está resolvido, obrigado por sua atenção.


All Articles