Yar*_*kee 19 python unit-testing
我是一名蟒蛇.在这些日子里,我正在驾驶自己对我项目中的一些核心模块进行更完整的单元测试.由于我们总是使用方法'assertEqual','assertTrue'等进行单元测试,所以这些方法都需要来自被测函数的返回值,我想知道如何在没有返回值的情况下对某些函数进行普通单元测试.
我想在这里展示一个小例子,如何在HelloTest中测试函数def foo(self,msg)?
class HelloTest(object):
def foo(self, msg):
MSG = msg.upper()
self.bar(MSG)
def bar(self, MSG):
print MSG
Run Code Online (Sandbox Code Playgroud)
ayc*_*dee 10
正如另一个提到的答案,您可以使用Python模拟库来对函数/方法的调用进行断言
from mock import patch
from my_module import HelloTest
import unittest
class TestFoo(unittest.TestCase):
@patch('hello.HelloTest.bar')
def test_foo_case(self, mock_bar):
ht = HelloTest()
ht.foo("some string")
self.assertTrue(mock_bar.called)
self.assertEqual(mock_bar.call_args[0][0], "SOME STRING")
Run Code Online (Sandbox Code Playgroud)
这会bar在HelloTest上修补该方法,并将其替换为记录针对它的调用的模拟对象.
嘲弄是一个兔子洞.只有在你必须这样做时才这样做,因为它确实使你的测试变得脆弱.例如,您永远不会注意到模拟对象的API更改.
我不太明白为什么每个人都想检查foo调用吧.
Foo具有一些功能,需要测试此功能.如果foo使用bar来做这件事不应该是我关注的问题.
期望的结果是在foo(msg)调用之后,将其msg.upper()发送到stdout.
您可以将stdout重定向到字符串缓冲区,并检查此字符串缓冲区的内容是否与您期望的内容相匹配.
例:
import sys
import unittest
from io import TextIOWrapper, BytesIO
class TestScript(unittest.TestCase):
def setUp(self):
self._old_stdout = sys.stdout
sys.stdout = TextIOWrapper(BytesIO(), sys.stdout.encoding)
def _output(self):
self._stdout.seek(0)
return self._stdout.read()
def test_foo(self):
hello_test = HelloTest()
hello_test.foo("blub")
self.assertEqual(self._output(), "BLUB")
def tearDown(self):
sys.stdout = self._old_stdout
self._stdout.close()
Run Code Online (Sandbox Code Playgroud)
您也可以为stdin执行此操作(并写入stdin以模拟某些输入),如果您需要执行任何特殊操作,则可以继承TestIOWrapper,例如允许在sys.stdout不使用的情况下发送非unicode文本sys.stdout.buffer(Python 2与Python 3) ).在这个SO答案中有一个例子.当您(仍然)仅使用Python 2时,那么使用StringIO可能比使用io模块更好.
感谢@Jordan 的介绍,我对此进行了编码并认为它是 HelloTest.foo 的可行单元测试
from mock import Mock
import unittest
class HelloTestTestCase(unittest.TestCase):
def setUp(self):
self.hello_test = HelloTest()
def tearDown(self):
pass
def test_foo(self):
msg = 'hello'
expected_bar_arg = 'HELLO'
self.hello_test.bar = Mock()
self.hello_test.foo(msg)
self.hello_test.bar.assert_called_once_with(expected_bar_arg)
if __name__ == '__main__':
unittest.main()
Run Code Online (Sandbox Code Playgroud)
您的代码可以如下所示,执行与上述相同的任务:
class HelloTest(object):
def foo(self, msg):
self.msg = msg.upper()
self.bar()
def bar(self):
print self.msg
Run Code Online (Sandbox Code Playgroud)
单元测试是:
from hello import HelloTest
import unittest
class TestFoo(unittest.TestCase):
def test_foo_case(self):
msg = "test"
ob = HelloTest()
ob.foo(msg)
expected = "TEST"
self.assertEqual(ob.msg, expected)
if __name__ == '__main__':
unittest.main(exit=False)
Run Code Online (Sandbox Code Playgroud)