2015-11-11 58 views
1

長話短說,我完全能夠模擬類方法,當它只是被模擬對象取代的方法時,但我無法在我試圖替換整個模型時嘲笑該方法模擬對象類嘲笑整個班級

@mock.patch.object成功嘲笑scan方法,但@mock.patch未能這樣做。我遵循 https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch 的例子,但顯然我做錯了什麼。

我嘲笑在這兩種情況下在同一個命名空間中的詞彙模塊(它是由import lexicon進口在sentence_parser),但mock_lexicon is lexicon.lexicon檢查失敗

#!python 
import sys; 
sys.path.append('D:\python\lexicon'); 
import lexicon; 

import sentence_parser; 
import unittest2 as unittest; 
import mock; 

class ParserTestCases(unittest.TestCase) : 

    def setUp(self) : 
     self.Parser = sentence_parser.Parser(); 

    @mock.patch('lexicon.lexicon') 
    def test_categorizedWordsAreAssigned_v1(self, mock_lexicon) : 

     print "mock is lexicon:"; 
     print mock_lexicon is lexicon.lexicon + "\n"; 

     instance = mock_lexicon.return_value; 
     instance.scan.return_value = "anything";  

     self.Parser.categorize_words_in_sentence("sentence"); 
     instance.scan.assert_called_once_with("sentence"); 

    @mock.patch.object(lexicon.lexicon, 'scan') 
    def test_categorizedWordsAreAssigned_v2(self, mock_scan) : 

     mock_scan.return_value = "anything";  

     self.Parser.categorize_words_in_sentence("sentence"); 
     mock_scan.assert_called_once_with("sentence"); 

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

輸出:

mock is lexicon: 
False 

====================================================================== 
FAIL: test_categorizedWordsAreAssigned_v1 (__main__.ParserTestCases) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "D:\python\get_img\getImage_env\lib\site-packages\mock\mock.py", line 1305, in patched 
    return func(*args, **keywargs) 
    File "./test_sentence_parser.py", line 26, in test_categorizedWordsAreAssigned_v1 
    instance.scan.assert_called_once_with("sentence"); 
    File "D:\python\get_img\getImage_env\lib\site-packages\mock\mock.py", line 947, in assert_called_once_with 
    raise AssertionError(msg) 
AssertionError: Expected 'scan' to be called once. Called 0 times. 

---------------------------------------------------------------------- 
Ran 2 tests in 0.009s 

FAILED (failures=1) 

編輯:

澄清,Parser定義如下

#!python 

import sys; 
sys.path.append('D:\python\lexicon'); 
import lexicon; 

class Parser(object) : 

    my_lexicon = lexicon.lexicon() 

    def __init__(self) : 
     self.categorized_words = ['test']; 

    def categorize_words_in_sentence(self, sentence) : 
     self.categorized_words = self.my_lexicon.scan(sentence); 


if (__name__ == '__main__') : 
    instance = Parser(); 
    instance.categorize_words_in_sentence("bear"); 
    print instance.categorized_words; 
+0

三個問題:1)我接過來一看,以'lexicon'模塊在https://github.com/bitprophet/lexicon/tree/master/lexicon和接縫給我的類是'Lexicon'代替' lexicon'; 2)我的猜測是你有另一個'詞庫'模塊,而不是'D:\ python \ lexicon'中的一個; 3)爲什麼你需要';'在行尾? –

+0

1)'詞庫'是我自己的模塊,恰好與你鏈接的名稱相同; 2)'D:\ python \ lexicon'中只有兩個文件,一個是'lexicon.py',另一個是包含unittests的'test_lexicon.py'; 3)';'只是我習慣於其他語言的東西,但這裏並沒有真正相關 – krzym1

回答

1

什麼是真正的與此有關的categorize_words_in_sentenceParser的方法如何使用lexicon。但首先,我們應該去除噪聲:

print mock_lexicon is lexicon.lexicon + "\n" 

是什麼導致我們錯誤的方向:嘗試通過

self.assertIs(mock_lexicon, lexicon.lexicon) 

來取代它,你會明白,你要打印False因爲mock_lexicon不是lexicon.lexicon + "\n",而只是lexicon.lexicon

現在我不能告訴你爲什麼第一次測試不起作用,因爲答案是categorize_words_in_sentence方法更可能是在sentence_parser模塊,我可以想你可以有類似

from lexicon import lexicon 

在這兩種情況下,採取一看Where to Patch文檔,可以啓發你什麼可以是你的原因,你真的需要補丁在你的情況。

第二個版本的工作原因是你修補的對象而不是參考(應該是不同的)。

最後更簡潔和普通版本可以是:

@mock.patch('lexicon.lexicon.scan', return_value="anything") 
def test_categorizedWordsAreAssigned_v3(self, mock_scan) : 
    self.Parser.categorize_words_in_sentence("sentence") 
    mock_scan.assert_called_once_with("sentence") 

一件事:至少你不使用Python 2.4刪除unittest2,並有興趣在回遷單元測試功能。

[編輯]

現在我可以停止猜測,並指向你,爲什麼第一個版本不工作,不會有任何效果:

class Parser(object) : 
    my_lexicon = lexicon.lexicon() 

Parser.my_lexicon屬性在評估加載時間爲。這意味着,當您導入sentence_parser時,會創建一個lexicon並與Parser.my_lexicon關聯。當你修補lexicon.lexicon時,你保持這個引用不變,你的解析器對象仍然使用導入時創建的原始引用。

你可以做什麼是

@patch("sentence_parser.Parser.my_lexicon") 

修補參考Parser類您可以使用create_autospect,如果你想給你的模擬的同lexicon簽名。

@patch("sentence_parser.Parser.my_lexicon", create_autospec("lexicon.lexicon", instance=True)) 
+0

我在原文中說過,詞彙只是通過'import lexicon;'導入的。我已將完整的「Parser」代碼添加到原始帖子中。我已經看到了哪裏補丁。我知道這隻能嘲笑'scan'方法,但它讓我很懊惱,嘲笑整個班級不工作時,沒有理由不去 – krzym1

+0

更新...... Parser的班級代碼是真正相關的。 –

+0

謝謝!它終於有效。我需要閱讀python的參考資料,我希望在補丁文檔的位置中會提到這種麻煩。 – krzym1