2017-08-05 44 views
1

我正在測試一個函數,它讀取一個文件,對內容進行操作並根據它看到的內容返回一個值。功能testme我測試生活在module.py。我正在運行Python 2.7。我知道我可以使用補丁修飾器和side_effect模擬文件讀取

import unittest 
import module 
from mock import patch, mock_open 

TestTestMe(unittest.TestCase): 
    ... 
    def test_test_me(self): 
     with patch('module.open', mock_open(read_data='1 2')) as _: 
      self.assertRaises(IndexError, module.testme, 'foo') 
     with patch('module.open', mock_open(read_data='1 2 3')) as _: 
      self.assertEquals(module.testme('foo'), 3) 

等做到這一點

不過,我想(主要是防止重複使用with語句,並且還能夠動態地生成各種的read_data)能夠使用@patch作爲裝飾器,使用函數定義我的read_data。像這樣的東西。我不會重複類定義和導入。

def give_contents(x): 
    if x == 'correct': 
     return mock_open(read_data='1 2 3') 
    else: 
     return mock_open(read_data='a b c') 

,然後使用測試功能,如:

@patch(module.open, side_effect=give_contents) 
def test_test_me(self): 
    self.assertEquals(module.testme('correct'), 3) 

我一直運行到TypeErrors如

TypeError: test_testme() takes exactly 1 argument (2 given) 

但是我設法解決這個問題。這真讓我抓狂。指導將不勝感激。如果你想要一些額外的細節,我可能已經省略了,請詢問具體細節,我會提供這些細節。

編輯:根據要求執行要測試的功能。對不起,我忽略這個「不重要」,顯然應該在那裏。

def testme(filepath): 
    with open(filepath, 'r') as f: 
     line = f.readline().strip().split() 
    return int(line[2]) 
+1

我不確定,因爲你沒有在你給我們的代碼中包含任何test_testme函數。但是,如果它是您使用的'module.testme'方法,則忘記在方法定義中聲明字符串參數。根據你的反饋,我可能會做出這個答案。 –

+0

這裏不要嘲笑。將「文件」對象轉換爲參數並讓其他代碼不單元測試打開文件可能會更好。然後,您可以將某種字符串IO對象作爲存根傳遞。即使你不能通過字符串IO,你仍然可以傳遞一個模擬參數來代替。 (即使我使用了一個,我可能也不會在模擬上聲明) – jpmc26

+0

@Alceste_我添加了實現。如果你寫了一個完整的答案,那將會很棒。 – user3274289

回答

0

我會考慮以下幾點:

from io import TextIOWrapper, BytesIO 
from unittest.mock import patch, mock_open 

def open_file(filename): 
    with open(filename, 'r') as f: 
     data = f.readline() 
    return data 

def string_byte_me(input): 
    return TextIOWrapper(BytesIO(input)) 

def side_effect(filename, mode): 
    if filename == 'correct': 
     return string_byte_me(b'1 2 3') 
    else: 
     return string_byte_me(b'a b c') 

m = mock_open() 
m.side_effect = side_effect 
@patch('builtins.open', m) 
def test_open_file(): 
    assert open_file('correct') == '1 2 3' 
    assert open_file('incorrect') == 'a b c' 
test_open_file() # Passes. 

這是通過實例化後加入side_effect到mock_open對象(不知道是否有更好的辦法?)。返回的side_effect必須能夠.readline(),因此是TextIOWrapper。

1

正如我在之前的評論中所述: 我不確定,因爲你沒有在你給我們的代碼中包含任何test_testme函數。但是,如果它是您正在使用的module.testme方法,則忘記在方法定義中聲明字符串參數。根據你的反饋,我可能會做出這個答案。

編輯:我並不完全在現場,因爲你忘記的論據更像是自我。

顯然,這對你有用,所以這裏是答應的答案。

假設你談到module.testme方法是看起來像一個函數:

TestTestMe(unittest.TestCase): 
... 
def testme(filepath): 
with open(filepath, 'r') as f: 
    line = f.readline().strip().split() 
return int(line[2]) 

這個功能,但是,而是一種方法,因爲你是從一個對象訪問它。 (做module.testme('foo')),並且因此,給該調用的第一個參數將始終是隱含的self。所以會發生的是,你的函數需要一個參數,一個字符串('foo'),但是即使self不明確也會給出兩個:'(self,'foo')'。

因此,錯誤,說你收到更多的論據比你要求。 更正很簡單:將self添加到testme的預期參數。

那麼這將成爲:

def testme(self, filepath): 
    with open(filepath, 'r') as f: 
     line = f.readline().strip().split() 
    return int(line[2]) 

希望這有助於。有關論點數量的錯誤往往是由於這種被遺忘的細節。雖然你不需要self,但它總是會作爲第一個參數傳入(在python中)。

祝您有美好的一天! PS:對不起,一些奇怪的英語短語和重複。