基于cmd模块为python3shell编写unittest
Writing unittest for python3 shell based on cmd module
我正在尝试为我的项目编写一些单元测试,但我在为 cmd 模块的功能编写单元测试时遇到问题。
我按照这个问题的例子:
让我们考虑以下问题:
#!/usr/bin/env python3
import cmd
import sys
class Interpreter(cmd.Cmd):
def __init__(self, stdin=sys.stdin, stdout=sys.stdout):
cmd.Cmd.__init__(self, stdin=stdin, stdout=stdout)
def do_show(self, args):
print("Hello world!")
if __name__ == "__main__":
interpreter = Interpreter()
interpreter.onecmd("show")
这是我的单元测试:
import unittest
import unittest.mock
import main
import sys
class CmdUiTest(unittest.TestCase):
def setUp(self):
self.mock_stdin = unittest.mock.create_autospec(sys.stdin)
self.mock_stdout = unittest.mock.create_autospec(sys.stdout)
def create(self):
return main.Interpreter(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_show_command(self):
cli = self.create()
cli.onecmd("show")
self.assertEqual("Hello world!", self._last_write(1))
如果我理解正确,正在创建 sys.stdin 和 sys.stdout 的单元测试模拟,并且使用方法 _last_write() 我应该能够访问参数列表使用 self.mock_stdout.write.call_args_list[-nr:]
写入模拟标准输出
测试结果
/home/john/rextenv/bin/python3 /home/john/pycharm/helpers/pycharm/utrunner.py /home/john/PycharmProjects/stackquestion/tests/test_show.py::CmdUiTest::test_show_command true
Testing started at 20:55 ...
Hello world!
Process finished with exit code 0
Failure
Expected :'Hello world!'
Actual :''
<Click to see difference>
Traceback (most recent call last):
File "/home/john/PycharmProjects/stackquestion/tests/test_show.py", line 25, in test_show_command
self.assertEqual("Hello world!", self._last_write(1))
AssertionError: 'Hello world!' != ''
- Hello world!
+
如你所见,Hello world! from do_show()
实际上打印到标准输出上。但由于某种原因 self.mock_stdout.write.call_args_list
总是 returns 空列表。
(顺便说一句。我是 运行 来自 Pycharm 的测试,但我也尝试从 shell 执行它们,没有区别)
我所需要的只是能够以某种方式测试我的 cmd 解释器的功能。只是比较打印输出。
我也尝试模拟内置打印,但这更破坏了我的测试(实际代码和测试更复杂)。但我不认为模拟打印和检查 called_with() 真的没有必要或正确的解决方案。模拟标准输出应该是可能的。
与orld有区别
不确定这是否是您想要的,last_write 肯定不起作用!
F
======================================================================
FAIL: test_show_command (__main__.CmdUiTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "./int.py", line 32, in test_show_command
self.assertEqual('Hello World!', fakeOutput.getvalue().strip())
AssertionError: 'Hello World!' != 'Hello world!'
- Hello World!
? ^
+ Hello world!
? ^
----------------------------------------------------------------------
Ran 1 test in 0.003s
FAILED (failures=1)
更改为使用 unitte.mock.patch - 我的 python 版本是 3.5
from unittest.mock import patch
from io import StringIO
# not working for reasons unknown
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:]))
# modified with unittest.mock.patch
def test_show_command(self):
# Interpreter obj
cli = self.create()
with patch('sys.stdout', new=StringIO()) as fakeOutput:
#print ('hello world')
self.assertFalse(cli.onecmd('show'))
self.assertEqual('Hello World!', fakeOutput.getvalue().strip())
我正在尝试为我的项目编写一些单元测试,但我在为 cmd 模块的功能编写单元测试时遇到问题。
我按照这个问题的例子:
让我们考虑以下问题:
#!/usr/bin/env python3
import cmd
import sys
class Interpreter(cmd.Cmd):
def __init__(self, stdin=sys.stdin, stdout=sys.stdout):
cmd.Cmd.__init__(self, stdin=stdin, stdout=stdout)
def do_show(self, args):
print("Hello world!")
if __name__ == "__main__":
interpreter = Interpreter()
interpreter.onecmd("show")
这是我的单元测试:
import unittest
import unittest.mock
import main
import sys
class CmdUiTest(unittest.TestCase):
def setUp(self):
self.mock_stdin = unittest.mock.create_autospec(sys.stdin)
self.mock_stdout = unittest.mock.create_autospec(sys.stdout)
def create(self):
return main.Interpreter(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_show_command(self):
cli = self.create()
cli.onecmd("show")
self.assertEqual("Hello world!", self._last_write(1))
如果我理解正确,正在创建 sys.stdin 和 sys.stdout 的单元测试模拟,并且使用方法 _last_write() 我应该能够访问参数列表使用 self.mock_stdout.write.call_args_list[-nr:]
测试结果
/home/john/rextenv/bin/python3 /home/john/pycharm/helpers/pycharm/utrunner.py /home/john/PycharmProjects/stackquestion/tests/test_show.py::CmdUiTest::test_show_command true
Testing started at 20:55 ...
Hello world!
Process finished with exit code 0
Failure
Expected :'Hello world!'
Actual :''
<Click to see difference>
Traceback (most recent call last):
File "/home/john/PycharmProjects/stackquestion/tests/test_show.py", line 25, in test_show_command
self.assertEqual("Hello world!", self._last_write(1))
AssertionError: 'Hello world!' != ''
- Hello world!
+
如你所见,Hello world! from do_show()
实际上打印到标准输出上。但由于某种原因 self.mock_stdout.write.call_args_list
总是 returns 空列表。
(顺便说一句。我是 运行 来自 Pycharm 的测试,但我也尝试从 shell 执行它们,没有区别)
我所需要的只是能够以某种方式测试我的 cmd 解释器的功能。只是比较打印输出。
我也尝试模拟内置打印,但这更破坏了我的测试(实际代码和测试更复杂)。但我不认为模拟打印和检查 called_with() 真的没有必要或正确的解决方案。模拟标准输出应该是可能的。
与orld有区别 不确定这是否是您想要的,last_write 肯定不起作用!
F
======================================================================
FAIL: test_show_command (__main__.CmdUiTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "./int.py", line 32, in test_show_command
self.assertEqual('Hello World!', fakeOutput.getvalue().strip())
AssertionError: 'Hello World!' != 'Hello world!'
- Hello World!
? ^
+ Hello world!
? ^
----------------------------------------------------------------------
Ran 1 test in 0.003s
FAILED (failures=1)
更改为使用 unitte.mock.patch - 我的 python 版本是 3.5
from unittest.mock import patch
from io import StringIO
# not working for reasons unknown
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:]))
# modified with unittest.mock.patch
def test_show_command(self):
# Interpreter obj
cli = self.create()
with patch('sys.stdout', new=StringIO()) as fakeOutput:
#print ('hello world')
self.assertFalse(cli.onecmd('show'))
self.assertEqual('Hello World!', fakeOutput.getvalue().strip())