Closed jgreub closed 6 years ago
I'm the OP of that stackoverflow thread. I got this working but forgot to update the thread.
There may be better ways but this is how I got it working.
You first need to override the default shell application runner to avoid getting stuck in the jline loop. You can do this by defining your own such as:
@Component
public class CliAppRunner implements ApplicationRunner {
public CliAppRunner() {
}
@Override
public void run(ApplicationArguments args) throws Exception {
//do nothing
}
}
Note that you will have to associate this custom Application runner against a "Test" profile so it overrides only during integration testing.
You then can write a test like this:
@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);
}
}
Note that the above test does not Assert anything. You will probably have to write your own little implementation of the ResultHandler interface that deals with parsing/formatting of the result so that it can be asserted.
Hope it helps.
Hey @girishla thanks for the tips, I managed to get it working with your help. Here's what I did:
@TestConfiguration
public class TestApplicationRunner implements ApplicationRunner {
private static Logger log = LoggerFactory.getLogger(TestApplicationRunner.class);
public TestApplicationRunner() {
log.info("Test Application Runner started!");
}
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("About to do nothing!");
// Do nothing...
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
@Import(TestApplicationRunner.class)
public class RecordScoreTest {
@Autowired
private Shell shell;
@Test
public void playerCanRecordEntireScoreOfGame() {
assertThat(shell.evaluate(() -> "record 7")).isEqualTo("Your bowling game score is 7! Well done!");
}
}
Notice the @Import(TestApplicationRunner.class)
annotation on the test class. By adding this configuration, the output in the console now looks like this:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.8.RELEASE)
2017-10-29 14:51:53.787 INFO 10232 --- [ main] c.j.bowlinggamekata.RecordScoreTest : Starting RecordScoreTest on JoeMacPro.local with PID 10232 (started by joe in /Users/joe/workspace/bowling-game-kata)
2017-10-29 14:51:53.788 INFO 10232 --- [ main] c.j.bowlinggamekata.RecordScoreTest : No active profile set, falling back to default profiles: default
2017-10-29 14:51:53.811 INFO 10232 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2d2ffcb7: startup date [Sun Oct 29 14:51:53 PDT 2017]; root of context hierarchy
2017-10-29 14:51:54.253 INFO 10232 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.shell.SpringShellAutoConfiguration' of type [org.springframework.shell.SpringShellAutoConfiguration$$EnhancerBySpringCGLIB$$a942d27c] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2017-10-29 14:51:54.269 INFO 10232 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'conversionService' of type [org.springframework.core.convert.support.DefaultConversionService] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2017-10-29 14:51:54.533 INFO 10232 --- [ main] c.j.b.helpers.TestApplicationRunner : Test Application Runner started!
2017-10-29 14:51:54.631 WARN 10232 --- [ main] org.jline : Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)
2017-10-29 14:51:54.806 INFO 10232 --- [ main] c.j.b.helpers.TestApplicationRunner : About to do nothing!
2017-10-29 14:51:54.807 INFO 10232 --- [ main] c.j.bowlinggamekata.RecordScoreTest : Started RecordScoreTest in 1.507 seconds (JVM running for 2.132)
2017-10-29 14:51:54.941 INFO 10232 --- [ Thread-2] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2d2ffcb7: startup date [Sun Oct 29 14:51:53 PDT 2017]; root of context hierarchy
Process finished with exit code 0
@girishla Your comment (https://github.com/spring-projects/spring-shell/issues/171#issuecomment-340267898) was incredibly helpful. Thanks!
@girishla In your solution you mentioned "Note that you will have to associate this custom Application runner against a "Test" profile so it overrides only during integration testing." How would you do that?
@tschuege you can use @ActiveProfiles annotation on your AppRunner implementation class or another easier way would be to use @TestConfiguration on it
Using this approach for me test was started, but not finished:
019-12-14 12:44:41.798 INFO 18872 --- [ main] c.z.a.TestApplicationRunner : Test Application Runner started! 2019-12-14 12:44:43.137 WARN 18872 --- [ main] org.jline : Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information) 2019-12-14 12:44:43.387 INFO 18872 --- [ main] c.demo.CommandTest : Started CommandTest in 2.548 seconds (JVM running for 3.448) shell:>
It actually seems that shell is opened during test execution and waiting for user input.
@zygimantus you should disable interactive into the SpringBootTest
properties
@SpringBootTest(properties = "spring.shell.interactive.enabled=false")
Hey, I just stumbled upon Spring Shell recently and I am unable to get a
@SpringBootTest
test to execute. The test attempts to begin, but hangs in the IntelliJ console as if a shell has been created and waiting for input.Test:
Console:
Here's a link to my tiny repo that acts as the simplest way to reproduce this issue: https://github.com/jgreub/bowling-game-kata I'm trying to use Spring Shell 2.0.0.M2 with Spring Boot 1.5.8.RELEASE
As a follow up
When it comes to actually testing a
@ShellMethod
, this stackoverflow post claims you use theShell#evaluate()
method. How do you obtain an instance ofShell
in a test?