在Python单元测试中,如何访问调用mock方法的实例?

问题描述 投票:0回答:1

我有一个类似于以下示例的 Python 类结构:


class Foo:
   def start(self):
     # do something

class FooBar(Foo):
   def __init__(self, param):
     self.param = param

   def run(self):
     # do something else

class ProductionClass:
   def use_foobar(self):
     foo = FooBar("string")
     foo.start()

现在我想编写一个测试,其中模拟

start
上的
FooBar
方法(继承自
Foo
),以便调用直接在
run
中定义的
FooBar
方法。

我试过这样:


def test_something(self):
    self.foobar_patcher = patch.object(FooBar, 'start', side_effect=self.mock_start)
    self.foobar_patcher.start()

    ProductionClass().use_foobar()

def mock_start(self):
    the_production_class_instance.run()

在此示例中,

the_production_class_instance
是调用
start()
方法的 FooBar 实例,但我似乎找不到获取此实例的方法。该实例在
ProductionClass().use_foobar()
内部创建,并在使用后丢弃,因此没有真正的方法从外部访问它。

有没有办法通过单元测试来实现这一点?

python python-unittest
1个回答
0
投票

对生产代码进行必要的更改

为了解决您的问题,我已将您的

ProductionClass
修改如下:

class ProductionClass:
    
    def __init__(self):
        self.foo = FooBar("string")
        
    def use_foobar(self):
        self.foo.start()

差异是:

  • 我创建了方法
    __init__()
    ,其中创建了属性
    foo
    作为
    FooBar
  • 的实例
  • 方法
    use_foobar()
    中只调用了继承自
    start()
    FooBar
    的方法
    Foo

所以我已将您的生产代码保存在以下文件

prod.py
中(除了在方法
Foo
FooBar
中引入
print()
指令之外,类
start()
run()
保持不变) :

class Foo:
   def start(self):
     # for execute the code I have substituted 'do_something' with a print()
     print("Foo.start() exec")

class FooBar(Foo):
   def __init__(self, param):
     self.param = param

   def run(self):
     # for execute the code I have substituted 'do_something' with a print()
     print("FooBar.run() exec")
     
class ProductionClass:
    
    def __init__(self):
        self.foo = FooBar("string")
        
    def use_foobar(self):
        self.foo.start()

测试代码

经过之前的修改,我认为下面的测试代码可以满足您的要求(代码保存在文件中

test_code.py
):

import unittest
from unittest.mock import patch
from prod import ProductionClass

class MyTestCase(unittest.TestCase):

    def test_something(self):
        prod_class = ProductionClass()
        foo_instance = prod_class.foo
        with patch.object(foo_instance, 'start') as mock_start:
            mock_start.start = foo_instance.run()
            prod_class.use_foobar()

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

测试执行的输出

如果我使用以下命令在终端中执行测试代码:

/path/to/python/interpreter/python /path/to/test/file/test_prod.py

我得到以下输出:

FooBar.run() exec
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

这证明它是执行

run()
的方法
FooBar
而不是
start()
的方法
Foo

© www.soinside.com 2019 - 2024. All rights reserved.