【问题标题】:How to test if another class method is called within a method in python?如何测试是否在python中的方法中调用了另一个类方法?
【发布时间】:2020-06-22 13:25:58
【问题描述】:

我有以下结构:

ClassB():
   def foo():

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

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

【问题讨论】:

    标签: python mocking python-unittest magicmock


    【解决方案1】:

    已编辑

    根据 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 时检查该方法是否已完全调用一次。

    测试说明

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

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

    mock系统的详细信息,建议阅读the official docs

    【讨论】:

    • 你确定它在补丁块内被调用了两次吗? assert_called_once 确实检查了一个电话。
    • @xiao,我不能只调用 A(),我应该将 B 作为 A(B) 传递给它,我应该传递 B 的模拟吗?
    • 好的。至于您的问题-您可以构造B 的实例并将其作为参数传递给A()。如果这不可能,您确实可以模拟ClassB 而不是ClassB.foo,并使用classb_mock.return_value.foo.assert_called... 代替。
    【解决方案2】:

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

    您可以自己编写 Mock。例如:

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

    然后使用 assert 检查 B_Mock 实例的 attr foo_calls

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-17
      • 2019-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多