2011-11-17 15 views
13

哪種方法適用於嘲笑和測試由open()返回的iters對象的代碼,使用mock庫?嘲諷python中的文件對象或迭代件

whitelist_data.py

WHITELIST_FILE = "testdata.txt" 

format_str = lambda s: s.rstrip().lstrip('www.') 
whitelist = None 

with open(WHITELIST_FILE) as whitelist_data: 
    whitelist = set(format_str(line) for line in whitelist_data) 

if not whitelist: 
    raise RuntimeError("Can't read data from %s file" % WHITELIST_FILE) 

def is_whitelisted(substr): 
    return 1 if format_str(substr) in whitelist else 0 

以下是我嘗試測試它。

import unittest 
import mock 

TEST_DATA = """ 
domain1.com 
domain2.com 
domain3.com 
""" 

class TestCheckerFunctions(unittest.TestCase): 

    def test_is_whitelisted_method(self): 
     open_mock = mock.MagicMock() 
     with mock.patch('__builtin__.open',open_mock): 
      manager = open_mock.return_value.__enter__.return_value 
      manager.__iter__ = lambda s: iter(TEST_DATA.splitlines()) 
      from whitelist_data import is_whitelisted 
      self.assertTrue(is_whitelisted('domain1.com')) 

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

python tests.py結果是:

$ python tests.py 

E 
====================================================================== 
ERROR: test_is_whitelisted_method (__main__.TestCheckerFunctions) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "tests.py", line 39, in test_is_whitelisted_method 
    from whitelist_data import is_whitelisted 
    File "/Users/supa/Devel/python/whitelist/whitelist_data.py", line 20, in <module> 
    whitelist = set(format_str(line) for line in whitelist_data) 
TypeError: 'Mock' object is not iterable 

---------------------------------------------------------------------- 
Ran 1 test in 0.001s 

UPD:感謝亞當,我已經重新安裝了模擬庫(pip install -e hg+https://code.google.com/p/mock#egg=mock)和更新tests.py。奇蹟般有效。

回答

15

您正在查找MagicMock。這支持迭代。

在模擬0.80beta4中,patch返回MagicMock。因此,這個簡單示例工作:

import mock 

def foo(): 
    for line in open('myfile'): 
     print line 

@mock.patch('__builtin__.open') 
def test_foo(open_mock): 
    foo() 
    assert open_mock.called 

如果你正在運行模擬0.7.x(它看起來像你),我不認爲你可以用補丁單獨做到這一點。您需要單獨創建模擬,然後將它傳遞到補丁:

import mock 

def foo(): 
    for line in open('myfile'): 
     print line 

def test_foo(): 
    open_mock = mock.MagicMock() 
    with mock.patch('__builtin__.open', open_mock): 
     foo() 
     assert open_mock.called 

注 - 我與py.test運行這些,然而,這些相同的方法將與單元測試正常工作。