简体   繁体   English

如何单元测试一个模块是否在另一个 function、Python 3 中实例化?

[英]How to unit test if a module is instantiated inside another function, Python 3?

I have a file my_work.py .我有一个文件my_work.py The class MyModel is used inside of the class MyWork 's run method. class MyModel在 class MyWorkrun方法中使用。 Suppose the functionality of MyModel is well tested by its own dedicated unit-tests.假设MyModel的功能通过它自己的专用单元测试得到了很好的测试。 My focus is to test if MyModel is used properly inside MyWork .我的重点是测试MyModel是否在MyWork中正确使用。

I need to test 2 things:我需要测试两件事:

  1. If MyModel is instantiated with given arguments.如果MyModel是用给定的 arguments 实例化的。
  2. If MyModel.run method is called.如果MyModel.run方法。 Because it is a long and expensive process, I have to mock it with fake returns.因为这是一个漫长而昂贵的过程,我不得不用虚假的回报来嘲笑它。

Note that, both classes MyModel and MyWork are defined in the same file my_work.py .请注意, MyModelMyWork两个类都定义在同一个文件my_work.py中。 This is just an example for this post.这只是这篇文章的一个例子。 In my real application, they are defined in different py-files.在我的实际应用程序中,它们是在不同的 py 文件中定义的。 Not sure if this can make a difference or not.不确定这是否会有所作为。

I have tried myself to write unit-test for it, but I could not make it.我已经尝试自己为它编写单元测试,但我做不到。 Could you please help me?请你帮助我好吗? See my test file test_my_work.py .请参阅我的测试文件test_my_work.py Thanks a lot in advance!提前非常感谢!

This is the file: my_work.py .这是文件: my_work.py

from typing import Tuple


class MyModel:
    def __init__(self, a: float, b: str):
        self._a = a
        self._b = b

    def run(self) -> Tuple[float, float]:
        # some long and expensive calculation.
        return self._a + 1, self._a + 2


class MyWork:
    def __init__(self, name: str):
        self._name = name
        self._res_1: float = 0
        self._res_2: float = 0

    def run(self) -> Tuple[float, float]:
        a = 2.5
        b = self._name
        model = MyModel(a=a, b=b)
        res_1, res_2 = model.run()
        return res_1, res_2

And this is the file: test_my_work.py .这是文件: test_my_work.py

import unittest
from unittest.mock import patch
from my_work import MyModel, MyWork


class TestMyWork(unittest.TestCase):

    @patch.object(MyModel, 'run', return_value=(3.5, 4.5))
    def test_if_my_model_run_is_called_in_my_work_run(self, mocked_run):
        self._my_work = MyWork(name='XX')
        self._my_work.run()
        mocked_run.assert_called_once()

    @patch.object(MyModel, '__init__')
    def test_if_my_model_is_initiated_in_my_work_run(self, mocked_init):
        self._my_work = MyWork(name='XX')
        self._my_work.run()
        mocked_init.assert_called_once_with(a=2.5, b='XX')


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

I would recommend to rather use the patch method instead of patch.object because MagicMock does not support mocking the __init__ method.我建议宁愿使用patch方法而不是patch.object因为MagicMock 不支持mocking 的__init__方法。

For the patch method, you'll need the "target" path to your class.对于patch方法,您需要 class 的“目标”路径。 In this case it will be 'my_work.MyModel' .在这种情况下,它将是'my_work.MyModel'

If you patch your model like this:如果您像这样修补 model:

    @patch('my_work.MyModel')
    def test_if_my_model_is_initiated_in_my_work_run(self, my_model_mock):
        ...

Then my_model_mock will be a mock of the class MyModel and will be replaced with MagicMock .然后my_model_mock将是 class MyModel的模拟,并将替换为MagicMock

my_model.return_value will be called when a new instance of MyModel is called. my_model.return_value将在调用MyModel的新实例时被调用。 The run method can then be mocked like this:然后可以像这样模拟run方法:

        my_model_mock.return_value.run.return_value = (3.5, 4.5)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM