簡體   English   中英

Python 單元測試模擬 class 和 class 方法

[英]Python unittest mock class and class method

我覺得這可能相對簡單,但我正在竭盡全力讓它發揮作用。 我想模擬整個 class,然后指定此類方法之一的返回值。

我已經看過這里和其他幾個問題,當然還有文檔 我仍然無法讓它工作。 請看下面我的簡單例子。

目錄tmp的內容:

tmp
├── __init__.py
├── my_module.py
└── test_my_module.py

my_module.py的內容:

class MyClass:
    def __init__(self):
        # Do expensive operations that will be mocked in testing.
        self.a = 7

    def my_method(self):
        # For sake of simple example, always return 1.
        return 1


def create_class_call_method():
    """Create MyClass instance and call its my_method method, returning
    the result."""
    instance = MyClass()
    value = instance.my_method()
    return value

test_my_module.py的內容:

import unittest
from unittest.mock import patch, Mock

from tmp import my_module


class MyClassTestCase(unittest.TestCase):

    def test_create_class_call_method(self):
        # Attempt to patch MyClass as well as specify a return_value for
        # the my_method method (spoiler: this doesn't work)
        with patch('tmp.my_module.MyClass',
                   my_method=Mock(return_value=2)):
            value = my_module.create_class_call_method()

        self.assertEqual(value, 2)


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

運行test_my_module.py的結果:

2 != <MagicMock name='MyClass().my_method()' id='140234477124048'>

Expected :<MagicMock name='MyClass().my_method()' id='140234477124048'>
Actual   :2

我嘗試過的其他一些事情:

  • 而不是..., my_method=Mock(return_value=2))patch語句中,像這樣解壓字典: **{'my_method.return_value': 2}
  • 嵌套with patch語句。 外部語句很簡單with patch('tmp.my_module.MyClass'):一樣,內部語句嘗試像這樣修補my_methodwith patch('tmp.my_module.MyClass.my_method, return_value=2)
  • 使用補丁裝飾器而不是上下文管理器
  • 將 patch 語句更改為with patch('tmp.my_module.MyClass') as p:然后在with語句中,嘗試像這樣設置pp.evaluate = Mock(return_value=2)

感謝您的幫助,謝謝。

我不確定create_class_call_method的實現,但請嘗試以下操作:

from unittest import mock

class MyClassTestCase(unittest.TestCase):
    @mock.patch('tmp.my_module.MyClass.my_method')
    @mock.patch('tmp.my_module.MyClass.__init__')
    def test_create_class_call_method(self, my_class_init, my_method_mock):
        my_class_init.return_value = None
        my_method.return_value = 2

        value = my_module.create_class_call_method()

        self.assertEqual(value, 2)

我找到了一個更好的解決方案。 簡而言之,我們需要模擬MyClass模擬的return_value 這是工作測試代碼:

import unittest
from unittest.mock import patch, Mock, MagicMock

from tmp import my_module


class MyClassTestCase(unittest.TestCase):

    def test_create_class_call_method(self):
        # Create a mock to return for MyClass.
        m = MagicMock()
        # Patch my_method's return value.
        m.my_method = Mock(return_value=2)

        # Patch MyClass. Here, we could use autospec=True for more
        # complex classes.
        with patch('tmp.my_module.MyClass', return_value=m) as p:
            value = my_module.create_class_call_method()

        # Method should be called once.
        p.assert_called_once()
        # In the original my_method, we would get a return value of 1.
        # However, if we successfully patched it, we'll get a return
        # value of 2.
        self.assertEqual(value, 2)


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

以及成功的結果:

Ran 1 test in 0.002s

OK

我認為在這個答案中找到了正確的方法

注意:下面是草圖 - 可能無法正確獲取 OP 的所有細節

import unittest
from unittest.mock import patch
from tmp import my_module

class MyClassTestCase(unittest.TestCase):

    @patch('tmp.my_module.MyClass')
    def test_create_class_call_method(self, my_class_mock):
       my_class_mock.return_value.my_method.return_value = 2
       value = my_module.create_class_call_method()
       self.assertEqual(value, 2)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM