Creating automated tests for an interactive shell based on the cmd module in Python

I am creating an interactive shell using Python 3 and the cmd module. I've already written simple unit tests using py.test to test individual functions like do_ * functions. I would like to create more comprehensive tests that actually interact with the shell itself, simulating user input. For example, how can I test the following simulated session:

bash$ console-app.py
md:> show options
  Available Options:
  ------------------
  HOST      The IP address or hostname of the machine to interact with
  PORT      The TCP port number of the server on the HOST
md:> set HOST localhost
  HOST => 'localhost'
md:> set PORT 2222
  PORT => '2222'
md:>

      

+3


source to share


2 answers


You can mock

input

either the input stream passed to the cmd to enter user input, but I find it easier and more flexible by checking it with the onecmd()

Cmd

API method and trusting how Cmd

to read the input. So you don't care how Cmd

to do the dirty work and check directly with the user command: I use Cmd

both with console and socket, and it doesn't bother me where the stream is coming from.

Also, I use onecmd()

to test even methods do_*

(and sometimes help_*

) and make my test less code-related.

Follow a simple use case. create()

and _last_write()

are helper methods for instantiation MyCLI

and take the last output lines accordingly.



from mymodule import MyCLI
from unittest.mock import create_autospec

class TestMyCLI(unittest.TestCase):
    def setUp(self):
        self.mock_stdin = create_autospec(sys.stdin)
        self.mock_stdout = create_autospec(sys.stdout)

    def create(self, server=None):
        return MyCLI(stdin=self.mock_stdin, stdout=self.mock_stdout)

    def _last_write(self, nr=None):
        """:return: last `n` output lines"""
        if nr is None:
            return self.mock_stdout.write.call_args[0][0]
        return "".join(map(lambda c: c[0][0], self.mock_stdout.write.call_args_list[-nr:]))

    def test_active(self):
        """Tesing `active` command"""
        cli = self.create()
        self.assertFalse(cli.onecmd("active"))
        self.assertTrue(self.mock_stdout.flush.called)
        self.assertEqual("Autogain active=False\n", self._last_write())
        self.mock_stdout.reset_mock()
        self.assertFalse(cli.onecmd("active TRue"))
        self.assertTrue(self.mock_stdout.flush.called)
        self.assertEqual("Autogain active=True\n", self._last_write())
        self.assertFalse(cli.onecmd("active 0"))
        self.assertTrue(self.mock_stdout.flush.called)
        self.assertEqual("Autogain active=False\n", self._last_write())

    def test_exit(self):
        """exit command"""
        cli = self.create()
        self.assertTrue(cli.onecmd("exit"))
        self.assertEqual("Goodbay\n", self._last_write())

      

Make sure to onecmd()

return True

if your cli should exit False

otherwise.

+3


source


Use python mock library to simulate user input. Here you will find similar problems with examples 1 , 2 .



+1


source







All Articles