2011-11-17 11 views
13

Quale modo è corretto per il codice di simulazione e test che l'oggetto di iter restituito da open(), utilizzando la libreria mock?Mocking di oggetti di file o iterables in 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 

Ecco come provo a testarlo.

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() 

Risultato di 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: Grazie alla biblioteca Adam, ho reinstallato finta (pip install -e hg+https://code.google.com/p/mock#egg=mock) e tests.py aggiornato. Funziona come un fascino.

risposta

15

Stai cercando un MagicMock. Questo supporta l'iterazione.

Nel simulato 0.80beta4, patch restituisce un MagicMock. Quindi questo semplice esempio funziona:

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 

Se si esegue 0.7.x finto (Sembra che siete), non credo che si può raggiungere questo obiettivo con la patch solo. Avrai bisogno di creare il mock separatamente, poi passarlo nella patch:

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 

Nota - Ho eseguito questi con py.test, tuttavia, questi stessi approcci funzioneranno con unittest pure.