在python中,如何在没有返回值的情况下对函数进行单元测试?

2024-05-16 19:18:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我是Python。在这些日子里,我正驱使自己在我的项目中的一些核心模块上做一个更完整的单元测试。 由于我们总是使用“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

Tags: 模块项目方法self核心foodefbar
3条回答

我不太明白为什么每个人都想检查foo叫bar

Foo有一些功能,这个功能需要测试。如果foo正在使用bar来做这件事,我不应该担心

期望的结果是,在调用foo(msg)之后,msg.upper()被发送到stdout

您可以redirect stdout to a string buffer并检查此字符串缓冲区的内容是否与您期望的内容匹配

例如:

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

您也可以对stdin这样做(并写入stdin以模拟某些输入),如果需要做任何特殊的事情,您可以将TestIOWrapper子类化,比如允许非unicode文本发送到sys.stdout,而不使用sys.stdout.buffer(Python2与Python3)。 在this SO answer中有一个例子。 当您(仍然)仅使用Python2时,使用StringIO可能比使用io模块更好

正如前面提到的另一个答案,您可以使用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")

这修补了HelloTest上的bar方法,并将其替换为记录针对它的调用的模拟对象

嘲弄有点像兔子洞。只有在你绝对必须的时候才去做,因为这会让你的测试变得脆弱。例如,您永远不会注意到模拟对象的API更改

在这种特殊情况下,我将模拟打印,然后在断言中使用模拟

在Python中,您将使用Mock package来模拟

相关问题 更多 >