Create automated tests for interactive shell based on Python's cmd module

给你一囗甜甜゛ 提交于 2020-01-04 04:13:24

问题


I am building an interactive shell using Python 3 and the cmd module. I have already written simple unit tests using py.test to test the individual functions, such as the do_* functions. I'd like to create more comprehensive tests that actually interact with the shell itself by simulating a user's input. For example, how could 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:>

回答1:


You can mock input or input stream passed to cmd to inject user input but I find more simple and flexible test it by onecmd() Cmd API method and trust how Cmd read input. In this way you cannot care how Cmd do the dirty work and test directly by users command: I use cmd both by console and socket and this I cannot care where the stream come from.

Moreover I use onecmd() to test even do_* (and occasionally help_*) methods and make my test less coupled to the code.

Follow a simple example of how I use it. create() and _last_write() are helper methods to build a MyCLI instance and take the last output lines respectively.

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())

Take care that onecmd() return True if your cli should terminate, False otherwise.




回答2:


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



来源:https://stackoverflow.com/questions/30056986/create-automated-tests-for-interactive-shell-based-on-pythons-cmd-module

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!