Schreiben von @ SpringBootTest-Tests bei Verwendung von Spring Shell in einer Anwendung

In Anwendungen ist es manchmal hilfreich, eine Konsole zum Verwalten der Anwendung direkt vom Server aus zu haben. Eine der äußerst praktischen Lösungen für dieses Problem ist Spring Shell.


Tests sind auch eine sehr gute Praxis (ich hoffe, Sie haben sie) und manchmal werden sie mit der Annotation @SpringBootTest geschrieben. Wenn Sie jedoch Spring Shell anschließen und versuchen, einen solchen Test auszuführen, ... friert Ihr Test in Erwartung eines Befehls von der Konsole einfach ein.


Wir suchen also nach einer Lösung.

Google


Nach einer kurzen Suche auf GitHub finden wir ein ähnliches Problem .


Zum Testen der Shell schlägt der Autor vor, den Bin mit dem ApplicationRunner-Typ zu überschreiben, der einen Befehl von der Konsole erwartet. Hier ist die Lösung für den Zugriff auf und das Testen der in @ShellComponent selbst definierten Befehle.


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

Leider warten die Tests mit dieser Lösung immer noch auf das Team.

Es ist Zeit, unter die Haube zu schauen!


Nach einem leichten Debug finden wir den folgenden Code in der SpringApplication-Klasse:


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

Mit anderen Worten, Spring Boot fügt einfach unseren Bin mit benutzerdefiniertem ApplicationRunner zu den bereits definierten hinzu und startet sie alle.

Es scheint, dass die Lösung einfach ist - definieren Sie den Behälter neu! Zeit, in die Spring Shell-Quelle einzusteigen.


Bohne neu definieren


Es wird schnell klar, dass die JLineShellAutoConfiguration-Klasse für die Erstellung der Läufer verantwortlich ist. Insbesondere interessiert uns die scriptApplicationRunner-Bean, die den Start unseres Tests verhindert.


, ( 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, jetzt scheint alles klar zu sein - gehen Sie zurück zu application.properties und schreiben Sie:


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

Drück die Daumen. Führen Sie den Test aus. Funktioniert.


Der Fall ist gelöst, danke für Ihre Aufmerksamkeit.


All Articles