我有一個 class A,它在其建構式中接收另一個 class B 的配置。然后通過使用此配置并創建 class 的實體來A創建一個變數。稍后在代碼中它將此變數稱為.BBself.b.do_somthing()
我怎樣才能確保這個方法呼叫實際上是用模擬/補丁呼叫的?下面我發布了一個超級簡單的虛擬代碼做類似的事情。我想測驗perform()實際呼叫的sing_a_song()
請注意代碼中的注釋
my_app.py
class Sing:
def __init__(self, **config):
self.songs = {
"almost home": """
Almost home
Brother, it won't be long
Soon all your burdens will be gone
With all your strength""",
"smooth criminal": """
Annie, are you okay?
So, Annie, are you okay? Are you okay, Annie?
"""
}
self.config = config
def sing_a_song(self, song_name):
return self.songs.get(song_name.lower())
class Singer:
def __init__(self, song_to_sing):
self.song_to_sing = song_to_sing
self.sing = Sing(**some_config_that_doesnt_matter) # <-- this part is the culprit
def perform(self):
if self.song_to_sing.lower() == "smooth criminal":
self.sing.sing_a_song(self.song_to_sing) # <-- and it's called here
else:
return "I don't know this song, not gonna perform."
和測驗(不起作用)
test.py
import unittest
from unittest.mock import patch
from my_app import Singer
class TestStringMethods(unittest.TestCase):
@patch("my_app.Sing", autospec=True)
def test_download(self, sing_mock):
melissa = Singer("smooth criminal")
melissa.perform()
sing_mock.assert_called() # <-- works (because of the call inside the constructor or bc of the call inside perform() ???
sing_mock.sing_a_song.assert_called() # <-- returns AssertionError: Expected 'sing_a_song' to have been called.
sing_mock.assert_called_with("smooth criminal") # <-- returns AssertionError: Expected call: Sing('smooth criminal') ... Actual call: Sing()
# If I do the following, the test passes, BUT if i after that REMOVE the actual
# call to self.sing.sing_a_song(self.song_to_sing), it still passes ??!?!!?
sing_mock.sing_a_song("smooth criminal")
if __name__ == "__main__":
unittest.main()
另外..我意識到呼叫實際上是對類而不是物件的方法進行的,就好像該方法是靜態的一樣,但是它沒有這樣定義,因此我需要以某種方式解決這個問題。
So.. what am I doing wrong, please help. I am still new the mocking and patching and I am quite confused no matter how many articles I read.
uj5u.com熱心網友回復:
如果您正在模擬一個類,并且想要檢查該類的方法呼叫,則必須在該類的實體上檢查它們。您在模擬上使用模擬的類實體return_value(通常為您提供呼叫運算子的結果,在類的情況下是類實體化)。請注意,實體化特定的類模擬將始終為您提供相同的“實體”(例如另一個模擬)。
因此,在您的情況下,以下內容將起作用:
class TestStringMethods(unittest.TestCase):
@patch("my_app.Sing", autospec=True)
def test_download(self, sing_mock):
melissa = Singer("smooth criminal")
melissa.perform()
sing_mock.assert_called() # this asserts that the class has been instantiated
sing_mock_instance = sing_mock.return_value # split off for readability
sing_mock_instance.sing_a_song.assert_called()
sing_mock_instance.sing_a_song.assert_called_with("smooth criminal")
uj5u.com熱心網友回復:
另一種方法適用于模擬整個班級Sing。但是,根據您要準確測驗的內容,您可能只想模擬特定方法:
class TestStringMethods(unittest.TestCase):
@patch('my_app.Sing.sing_a_song')
def test_download(self, sing_a_song_mock):
melissa = Singer('smooth criminal')
melissa.perform()
sing_a_song_mock.assert_called() # this works
sing_a_song_mock.assert_called_with('smooth criminal') # works, too
例如,當您已經知道在其他測驗中測驗了類的實體化并且您現在只想在當前測驗中測驗類方法的確切呼叫時,這在某些情況下可能很有用。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/438722.html
標籤:python-3.x unit-testing pytest python-unittest
上一篇:linux命令之wget下載
