使用Python unittest测试回调调用的正确方法是什么?

6 投票
1 回答
7885 浏览
提问于 2025-04-17 21:30

我有一段应用程序代码,长得像这样。

# Filename: app.py
class Foo:
    def __init__(self):
        self.callback = None

    def set_handler(self, callback):
        self.callback = callback

    def run(self, details):
        name, age = details.split('/')
        if age.isdigit():
            age = int(age)
        else:
            age = -1
        return self.callback(name, age)

从中可以看到,它提供了一个叫做 set_handler 的方法,用来设置一个回调函数。这个回调函数在后面需要用两个参数来调用:一个字符串和一个整数。我正在尝试在单元测试中确保这一点。

# Filename: test_app.py
import unittest
from app import Foo

class AppTest(unittest.TestCase):
    def f(self, a, b):
        # This callback should get called with the first argument as
        # string and the second argument as integer
        return repr(a) + ',' + repr(b)

    def test_callback(self):
        foo = Foo()
        foo.set_handler(self.f)
        self.assertEqual(foo.run('John/20'), "'John',20")
        self.assertEqual(foo.run('John/xyz'), "'John',-1")

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

这个单元测试是成功的。但我觉得我的测试方法不够稳健。这个单元测试基本上有点像是个小把戏,因为我不知道怎么正确地测试回调函数是否用正确类型的参数被调用。我觉得奇怪的是,AppTest 的 f 方法在进行类型检查时,试图返回一个由参数的 repr() 组成的值,这样做根本不够稳健。

你能帮我吗?有没有办法让 f 方法不再负责测试类型的问题?

1 个回答

15

编辑:

试试使用 unittest.mock(这是Python 3.3自带的库)。它可以让你检查方法是如何被调用的。比如:

import unittest
from unittest.mock import Mock

from app import Foo

class AppTest(unittest.TestCase):

    def test_callback(self):
        foo = Foo()
        f = Mock()
        foo.set_handler(f)

        foo.run('John/20')
        f.assert_called_with('John', 20)

        foo.run('John/xyz')
        f.assert_called_with('John', -1)

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

撰写回答