为单元测试断言 `mocked_function.called`

Asserting `mocked_function.called` for unittest

我正在为 PySide UI 实现单元测试,但无法弄清楚如何正确断言连接到 ui 元素的函数已被调用。

到目前为止,我已经尝试了不同的方法来导入我正在为其编写测试的模块。模拟函数的不同方式

../app/ui.py

import sys

from PySide.QtGui import *
from PySide.QtCore import *

def btn1_callback():
    print("1")

class Window(QWidget):
    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)

        layout = QVBoxLayout()

        self.btn1 = QPushButton("Foo")
        self.btn1.clicked.connect(btn1_callback)

        layout.addWidget(self.btn1)
        self.setLayout(layout)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    app.exec_()

../tests/test_ui.py

import sys
import unittest
import mock

from PySide.QtGui import *
from PySide.QtCore import *
from PySide.QtTest import QTest

import app.ui

application = QApplication(sys.argv)

class UiTest(unittest.TestCase):

    def setUp(self):
        self.ui = app.ui.Window()

    @mock.patch.object(app.ui, "btn1_callback")
    def test_btn1(self, callback):
        QTest.mouseClick(self.ui.btn1, Qt.LeftButton)
        self.assertTrue(callback.called)

if __name__ == '__main__':
    unittest.main()

运行 python -m unittest discover tests 将 运行 1 测试失败,表示未调用该函数。但是它会在控制台上打印“1”,所以我知道 QTest 确实设法导致执行回调。

patch.object 基本上修改了对名称 app.ui.btn1_callback 解析的访问权限。但是,在 after app.ui.Window() 已经获得对该函数的引用之前,您不会调用它。该参考不受补丁影响。您必须在补丁仍然有效时实例化 UI 和 运行 测试:

class UiTest(unittest.TestCase):
    def setUp(self):
        p = mock.patch.object(app.ui, "btn1_callback")
        self.addCleanup(p.stop)
        self.callback = p.start()
        self.ui = app.ui.Window()

    def test_btn1(self):
        QTest.mouseClick(self.ui.btn1, Qt.LeftButton)
        self.assert(self.callback.called)

现在 startup 负责启用补丁,并安排其最终禁用。 Window() 和测试本身 运行 在回调已被修补的环境中。

(使用 addCleanup 比定义 tearDown 调用 p.stop() 更安全,因为它确保即使 tearDown 因任何原因未被调用也能停止补丁。 )