如何测试另一个 class 方法是否在 python 的方法中被调用?

How to test if another class method is called within a method in python?

我有以下结构:

ClassB():
   def foo():

Class A():
   def __init__(self, B):
       #some initialisations
   def method1():
       #complex logic
       B.foo()

我正在尝试编写单元测试方法 1 并想测试 foo 是否被调用一次。 我怎样才能做到这一点?我应该嘲笑什么?

您应该为 B 创建一个 Mock,将其传递给 A 的构造函数并检查该函数是否被调用一次。

你可以自己写Mock。例如:

class B_Mock():
    def __init__(self):
       self.foo_calls = 0

    def foo(self):
        self.foo_calls += 1

然后用 assert

检查 B_Mock 实例的属性 foo_calls

已编辑

根据 OP 提供的进一步信息,对答案进行了返工。

代码

下面的代码已经在CentOS 8 上用Python3.8.3 进行了本地测试。运行 python3 -m unittest 查看测试结果。

功能代码(sub.py):

class B():                                                                                                                                                                                                         
    def foo(self):                                                                                                                                                                                                 
        pass                                                                                                                                                                                                       
                                                                                                                                                                                                                   
                                                                                                                                                                                                                   
class A():                                                                                                                                                                                                         
    def __init__(self, B):                                                                                                                                                                                         
        self.b = B                                                                                                                                                                                                 
                                                                                                                                                                                                                   
    def method1(self):                                                                                                                                                                                             
        self.b.foo()

测试代码(test.py):

from unittest import TestCase                                                                                                                                                                                      
from unittest.mock import patch                                                                                                                                                                                    
                                                                                                                                                                                                                   
from sub import A, B                                                                                                                                                                                               
                                                                                                                                                                                                                   
                                                                                                                                                                                                                   
class Test(TestCase):                                                                                                                                                                                              
    def test_A(self):                                                                                                                                                                                              
        with patch('sub.B.foo') as mock_foo:                                                                                                                                                                       
            a = A(B)                                                                                                                                                                                               
            a.method1()                                                                                                                                                                                            
            mock_foo.assert_called_once()

基本上,测试代码会尝试模拟 B.foo 方法,并在 A.method1 被调用时检查该方法是否被调用了 EXACTLY ONCE。

测试说明

  1. a = A(B)线路不调用B.foo
  2. a.method1() 线路调用 B.foo

总共调用了 B.foo 一次,因此 mock_foo.assert_called_once() 将通过。如果上述任何参数被证明是无效的,则断言将失败。如果您只需要检查 B.foo 是否至少被调用一次,请改用 mock_foo.assert_called()

关于模拟系统的细节,我建议阅读the official docs