簡體   English   中英

模擬在測試方法中實例化的Python類

[英]Mocking a Python class that is instantiated in method under test

我有一個受測試的系統(下面的類Printer ),它使用另一個類(下面的Class ContentContainer )。 在一個方法(下面的方法retrieve_and_show_content )中,實例化此類。 在這個方法的測試中(下面的方法test_printer_03 ),我想實例化一個mock而不是真正的類。 但是,它不會像這樣工作。

在這里讀到我應該更改名稱指向的對象與另一個。 看起來我要替換的對象的名稱只是ContentContainer ,而我實際替換的對象的名稱是TestMockClass.ContentContainer 這個觀察是否正確? 如果是這樣,我該如何更改? 如果我只是在patch語句中刪除前綴TestMockClass ,我會得到一個TypeError: Need a valid target to patch. You supplied: 'ContentContainer' TypeError: Need a valid target to patch. You supplied: 'ContentContainer'

#TestMockClass.py
import unittest
from mock import Mock, patch

class Printer():
    def __init__(self, name, cc):
        self.name = name
        self.cc = cc
    def show_content(self):
        text = '{0} says: {1}'.format(self.name, self.cc.content())
        return text
    def retrieve_and_show_content(self):
        cc_tmp = ContentContainer()
        text = '{0} says: {1}'.format(self.name, cc_tmp.content())
        return text

class ContentContainer():
    def __init__(self):
        self.method_counter()
    def content(self):
        return 'Content from ContentContainer'
    def method_counter(self):
        pass

class Test(unittest.TestCase):

    '''No mocking'''
    def test_printer_01(self):
        cc = ContentContainer()
        sut = Printer('P01', cc)
        result = sut.show_content()
        expected_result = 'P01 says: Content from ContentContainer'
        self.assertEqual(result, expected_result, 
                         msg = '\nRetrieved:\n{0} \nExpected:\n{1}'.format(result, expected_result))
        result = sut.retrieve_and_show_content()
        expected_result = 'P01 says: Content from ContentContainer'
        self.assertEqual(result, expected_result, 
                         msg = '\nRetrieved:\n{0} \nExpected:\n{1}'.format(result, expected_result))

    '''Create a mock object, which is the input of the method under test'''
    def test_printer_02(self):
        mock_cc = Mock()
        mock_cc.content.return_value = 'Mocked content'
        sut = Printer('P02', mock_cc)
        result = sut.show_content()
        expected_result = 'P02 says: Mocked content'
        self.assertEqual(result, expected_result, 
                         msg = '\nRetrieved:\n{0} \nExpected:\n{1}'.format(result, expected_result))
        self.assertFalse(mock_cc.method_counter.called, 'Method method_counter shall not be called')

    '''Create a mock class, which is instantiated inside the method under test'''
    @patch('TestMockClass.ContentContainer')
    def test_printer_03(self, mock_cc):
        mock_cc.content.return_value = 'Mocked content'
        sut = Printer('P03', mock_cc)
        result = sut.retrieve_and_show_content()
        expected_result = 'P03 says: Mocked content'
        self.assertEqual(result, expected_result, 
                         msg = '\nRetrieved:\n{0} \nExpected:\n{1}'.format(result, expected_result))
        self.assertFalse(mock_cc.method_counter.called, 'Method method_counter shall not be called')

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

運行此單元測試時,輸出為:

AssertionError: 
Retrieved:
P03 says: Content from ContentContainer 
Expected:
P03 says: Mocked content

兩件事情:

  1. 因為ContentContainer現在與測試位於同一個文件中,所以實際上需要修補__main__.ContentContainer

     @patch('__main__.ContentContainer') 
  2. 因為ContentContainer是一個類,並且您在該類的實例上調用content ,所以您實際上希望模擬該實例上的content ,而不是類。 因此,您需要執行以下操作: mock_cc.return_value.content.return_value = 'Mocked content' (請注意其中的附加.return_value以確保您正在.return_value實例,而不是類)。 這是因為調用類會創建一個實例。 因此,實例是類上調用的返回值。

因此測試應如下所示:

@patch('__main__.ContentContainer')
def test_printer_03(self, mock_cc):
    mock_cc.return_value.content.return_value = 'Mocked content'
    ...

暫無
暫無

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

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