基于 Python 的 cmd 模块为交互式 shell 创建自动化测试
Create automated tests for interactive shell based on Python's cmd module
我正在使用 Python 3 和 cmd 模块构建交互式 shell。我已经使用 py.test 编写了简单的单元测试来测试各个函数,例如 do_* 函数。我想创建更全面的测试,通过模拟用户的输入实际与 shell 本身交互。例如,我如何测试以下模拟会话:
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:>
使用pythonmock library to simulate user input. Here you will find similar problems with examples 1, 2。
您可以 mock
input
或传递给 cmd 的输入流来注入用户输入,但我发现通过 onecmd()
Cmd
[=35 进行测试更简单灵活=] 方法并相信 Cmd
如何读取输入。通过这种方式,您不必关心 Cmd
如何通过用户命令直接进行脏工作和测试:我通过控制台和套接字使用 cmd
并且我不关心流来自哪里。
此外,我使用 onecmd()
来测试甚至 do_*
(偶尔 help_*
)方法,并使我的测试与代码的耦合度降低。
按照我如何使用它的简单示例进行操作。 create()
和 _last_write()
是构建 MyCLI
实例并分别获取最后输出行的辅助方法。
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())
注意 onecmd()
return True
如果你的 cli 应该终止,False
否则。
我正在使用 Python 3 和 cmd 模块构建交互式 shell。我已经使用 py.test 编写了简单的单元测试来测试各个函数,例如 do_* 函数。我想创建更全面的测试,通过模拟用户的输入实际与 shell 本身交互。例如,我如何测试以下模拟会话:
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:>
使用pythonmock library to simulate user input. Here you will find similar problems with examples 1, 2。
您可以 mock
input
或传递给 cmd 的输入流来注入用户输入,但我发现通过 onecmd()
Cmd
[=35 进行测试更简单灵活=] 方法并相信 Cmd
如何读取输入。通过这种方式,您不必关心 Cmd
如何通过用户命令直接进行脏工作和测试:我通过控制台和套接字使用 cmd
并且我不关心流来自哪里。
此外,我使用 onecmd()
来测试甚至 do_*
(偶尔 help_*
)方法,并使我的测试与代码的耦合度降低。
按照我如何使用它的简单示例进行操作。 create()
和 _last_write()
是构建 MyCLI
实例并分别获取最后输出行的辅助方法。
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())
注意 onecmd()
return True
如果你的 cli 应该终止,False
否则。