Search code examples
javatestingprocessbuilderjline

how to test a jline based console application


I'm trying to test a console application that uses jline for handling interaction with the user.

I'm starting the application using ProcessBuilder which gives me access to the application's:

I was expecting to use a workflow similar to this:

  • Start Application
  • Read Output until I see the application's prompt >
  • Send Input for my test case, e.g. login
  • Read Output until I see the expect response, e.g. Username:
  • and so on

However, the test just freezes. Stepping through the code, it appears that jline is freezing on JNI calls to _getch on Windows. I'm guessing that the problem is because I am running Java from ProcessBuilder which is headless so there is no console and that is confusing windows. Setting -Djline.terminal=jline.UnsupportedTerminal as per the Jline docs doesn't help either.

I've found a thread discussing Python pexpect for testing a (non-java) readline application.

Question: how can I test a jline based application using just java tools?


Solution

  • I gave up on trying to test just using java tools and went with using the python pexpect library to execute the console application. The tests were integrated into the maven build, but required a *nix host to run them:

    import unittest
    import pexpect
    import os
    import signal
    import subprocess
    import urllib
    import urllib2
    import json
    
    from wiremock import WiremockClient
    
    class TestInteractive(unittest.TestCase):
    
        cli_cmd = "java -jar " + os.environ["CLI_JAR"]
    
        # ... code omitted for brevity 
    
        def test_interactive_mode_username_and_password_sent_to_server(self):
            child = pexpect.spawn(TestInteractive.cli_cmd, timeout=10)
            child.expect   ('Username: ')
            child.sendline ('1234')
            child.expect   ('Password: ')
            child.sendline ('abcd')
            child.expect   ('Successfully authenticated')
            child.expect   ('stratos> ')
            child.sendline ('exit')
            child.expect   (pexpect.EOF)
            # CLI sends GET request to mock server url /stratos/admin/coookie
            self.assertEqual(self.wiremock.get_cookie_auth_header(), "1234:abcd")
    
        # ... code omitted for brevity
    
    if __name__ == '__main__':
        try: 
            unittest.main()
        # handle CTRL-C
        except KeyboardInterrupt:
            # shut down wiremock 
            TestInteractive.wiremock.stop()
            exit(1) 
    

    The full CLI test suite for the project I was working on can be found here.