簡體   English   中英

使用 python 的模擬 patch.object 更改在另一個方法中調用的方法的返回值

[英]Using python's mock patch.object to change the return value of a method called within another method

是否可以模擬在我嘗試測試的另一個函數中調用的函數的返回值? 我希望模擬方法(將在我測試的許多方法中調用)每次調用時都返回我指定的變量。 例如:

class Foo:
    def method_1():
       results = uses_some_other_method()
    def method_n():
       results = uses_some_other_method()

在單元測試中,我想使用 mock 來更改uses_some_other_method()的返回值,以便任何時候在Foo調用它時,它都會返回我在@patch.object(...)定義的內容

有兩種方法可以做到這一點; 帶補丁和帶 patch.object

Patch 假定您不是直接導入對象,而是您正在測試的對象正在使用它,如下所示

#foo.py
def some_fn():
    return 'some_fn'

class Foo(object):
    def method_1(self):
        return some_fn()
#bar.py
import foo
class Bar(object):
    def method_2(self):
        tmp = foo.Foo()
        return tmp.method_1()
#test_case_1.py
import bar
from mock import patch

@patch('foo.some_fn')
def test_bar(mock_some_fn):
    mock_some_fn.return_value = 'test-val-1'
    tmp = bar.Bar()
    assert tmp.method_2() == 'test-val-1'
    mock_some_fn.return_value = 'test-val-2'
    assert tmp.method_2() == 'test-val-2'

如果是直接導入待測模塊,可以使用patch.object如下:

#test_case_2.py
import foo
from mock import patch

@patch.object(foo, 'some_fn')
def test_foo(test_some_fn):
    test_some_fn.return_value = 'test-val-1'
    tmp = foo.Foo()
    assert tmp.method_1() == 'test-val-1'
    test_some_fn.return_value = 'test-val-2'
    assert tmp.method_1() == 'test-val-2'

在這兩種情況下,在測試功能完成后 some_fn 將被“取消模擬”。

編輯:為了模擬多個函數,只需向函數添加更多裝飾器並添加參數以接收額外的參數

@patch.object(foo, 'some_fn')
@patch.object(foo, 'other_fn')
def test_foo(test_other_fn, test_some_fn):
    ...

請注意,裝飾器越接近函數定義,它在參數列表中的位置就越早。

這可以通過這樣的事情來完成:

# foo.py
class Foo:
    def method_1():
        results = uses_some_other_method()


# testing.py
from mock import patch

@patch('Foo.uses_some_other_method', return_value="specific_value"):
def test_some_other_method(mock_some_other_method):
    foo = Foo()
    the_value = foo.method_1()
    assert the_value == "specific_value"

這是您可以閱讀的來源:在錯誤的地方打補丁

讓我澄清一下你在說什么:你想在一個測試用例中測試Foo ,它調用外部方法uses_some_other_method 您想要模擬返回值,而不是調用實際方法。

class Foo:
    def method_1():
       results = uses_some_other_method()
    def method_n():
       results = uses_some_other_method()

假設上面的代碼在foo.pyuses_some_other_method在模塊bar.py定義。 這是單元測試:

import unittest
import mock

from foo import Foo


class TestFoo(unittest.TestCase):

    def setup(self):
        self.foo = Foo()

    @mock.patch('foo.uses_some_other_method')
    def test_method_1(self, mock_method):
        mock_method.return_value = 3
        self.foo.method_1(*args, **kwargs)

        mock_method.assert_called_with(*args, **kwargs)

如果你想每次傳入不同的參數時都改變返回值, mock提供了side_effect

為了添加有用的 Silfheed 答案,我需要修補相關對象的多個方法。 我發現這樣做更優雅:

給定以下要測試的函數,位於module.a_function.to_test.py

from some_other.module import SomeOtherClass

def add_results():
    my_object = SomeOtherClass('some_contextual_parameters')
    result_a = my_object.method_a()
    result_b = my_object.method_b()
    
    return result_a + result_b

為了測試這個函數(或類方法,無關緊要),可以通過使用patch.object()sys.modules來修補類SomeOtherClass的多個方法:

@patch.object(sys.modules['module.a_function.to_test'], 'SomeOtherClass')
def test__should_add_results(self, mocked_other_class):
  mocked_other_class().method_a.return_value = 4
  mocked_other_class().method_b.return_value = 7

  self.assertEqual(add_results(), 11)

無論您需要修補的SomeOtherClass的方法數量如何,這都有效,並具有獨立的結果。

此外,使用相同的修補方法,如果需要,可以返回SomeOtherClass的實際實例:

@patch.object(sys.modules['module.a_function.to_test'], 'SomeOtherClass')
def test__should_add_results(self, mocked_other_class):
  other_class_instance = SomeOtherClass('some_controlled_parameters')
  mocked_other_class.return_value = other_class_instance 
  ...

暫無
暫無

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

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