Python-mock:如何测试是否调用了super()

10 投票
2 回答
7723 浏览
提问于 2025-04-18 16:05

我有以下结构:

class A(Object):
    def method(self):
        return 'a'

class B(A):
   def __init__(self, test):
       self.test = test

   def method(self):
        if self.test:
           return super(A, self).method(self)
        else:
           return 'b'

我想做的是写一个测试用例,来检查如果 self.test 为真,那么父类的函数和 A 类的方法都被调用了。

我该怎么做呢?我应该模拟什么?

进阶问题:如果 A 类和 B 类在不同的模块里,而且它们的名字是一样的。这样的话,我就会写成:class A(module1.A):这样会影响模拟的方式吗?

2 个回答

0

为了进一步说明@Malina的精彩回答,如果你无法对模块A的方法进行修改(比如A是在一个第三方库中,属于一个复杂的旧系统,或者是在运行时动态创建的等等),你仍然可以通过在类B中创建另一个专门用于测试的方法来测试这个功能。

修改后的类 B

import A

class B(A):
   def __init__(self, test):
       self.test = test

   def method(self):
        if self.test:
           self._delegate_to_A()  # Move the super call to a separate method
        else:
           return 'b'
   
   def _delegate_to_A(self)
       return super(A, self).method(self)

修改后的类 B 的测试代码

import mock, unittest

class TestB(unittest.TestCase):

    # Patch B's `delegate` method instead of A
    @mock.patch("B._delegate_to_A")
    def test_super_method(self, mock_super):
        B(True).method()
        self.assertTrue(mock_super.called)

    @mock.patch("B._delegate_to_A")
    def test_super_method(self, mock_super):
        B(False).method()
        self.assertFalse(mock_super.called)
12

正如@MartijnPieters所说,测试是否调用了super通常是检查实现细节,而不是测试一个合约。不过,有时候检查具体的实现也是有必要的,或者父类可能有要求必须调用super的合约。为了测试是否调用了super,可以使用一个模拟对象,正如@mgilson提到的。下面是详细的说明:

import mock, unittest

class TestB(unittest.TestCase):

    @mock.patch("A.method")
    def test_super_method(self, mock_super):
        B(True).method()
        self.assertTrue(mock_super.called)

    @mock.patch("A.method")
    def test_super_method(self, mock_super):
        B(False).method()
        self.assertFalse(mock_super.called)

你需要在补丁中指定完整的命名空间。例如,@mock.patch("module.submodule.A.method")。这可以用于A类中的任何方法,包括__init__;语法是完全一样的。

撰写回答