spring-projects / spring-shell

Spring based shell
http://projects.spring.io/spring-shell/
Apache License 2.0
732 stars 396 forks source link

Suggestion for solving the REPL stuck problem during integration tests #203

Open ghost opened 6 years ago

ghost commented 6 years ago

In the main documentation it says:

Given that Spring Shell will kick in and start the REPL by virtue of this dependency being present, you’ll need to either build skipping tests (-DskipTests) throughout this tutorial or remove the sample integration test that was generated by start.spring.io. If you don’t do so, the integration test will create the Spring ApplicationContext and, depending on your build tool, will stay stuck in the eval loop or crash with a NPE.

But I have solved it in my project differently and got the test running using this:

In my main test class I import an ApplicationRunner class that basically exits right away. Given the highest priority, it is chosen over the default Spring Shell runner.

@RunWith(SpringRunner.class)
@SpringBootTest
@Import(TestShellApplicationRunner.class)
public class MyShellTests {

    @Autowired
    private Shell shell;

    @Test
    public void contextLoads() {
        assertNotNull(shell);

        Object help = shell.evaluate(() -> "help");
        assertNotNull(help);
        System.out.println(help);
    }
}

Here is the TestShellApplicationRunner class

@TestConfiguration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class TestShellApplicationRunner implements ApplicationRunner {

    private static final Logger LOG = LoggerFactory.getLogger(TestShellApplicationRunner.class);

    @Override
    public void run(ApplicationArguments args) throws Exception {
        LOG.info("Test Shell Application started.");
    }
}

I left out the imports for brevity.

This way, the test runs, you can even execture command, like I do here with the help command, and make asserts and the test exits cleanly.

I think it would be a good idea to include this way in the general approach and then the warning above can be removed and replaced with this suggestion on how to test the Spring Shell commands.

-Stefan

ghost commented 6 years ago

oh, while I was writing this - how I solved it with Spring Shell 2.0.0.M1 - I updated my application to 2.0.0.RELEASE and let the build run - and I go back and it doesn't work anymore. It hangs like it's written in the documentation...

So, I need to investigate what changed since then....

ghost commented 6 years ago

OK, I see, in this commit f90edd42c41c738ed628805922c850c9b05c6730

you changed from @ConditionalOnMissingBean(ApplicationRunner.class) to @ConditionalOnProperty(prefix = SPRING_SHELL_INTERACTIVE, value = InteractiveShellApplicationRunner.ENABLED, havingValue = "true", matchIfMissing = true) and @ConditionalOnProperty(prefix = SPRING_SHELL_SCRIPT, value = ScriptShellApplicationRunner.ENABLED, havingValue = "true", matchIfMissing = true)

....which actually makes it even simpler by adding these properties to the @SpringBootTest annotation. Then the custom ApplicationRunner is no longer needed.

Minimalistic example (without imports):

@RunWith(SpringRunner.class)
@SpringBootTest(properties = {
        InteractiveShellApplicationRunner.SPRING_SHELL_INTERACTIVE_ENABLED + "=false",
        ScriptShellApplicationRunner.SPRING_SHELL_SCRIPT_ENABLED + "=false"
})
public class MyShellTests {

    @Autowired
    private Shell shell;

    @Test
    public void contextLoads() {
        Object help = shell.evaluate(() -> "help");
        assertNotNull(help);
        System.out.println(help);
    }
}