2011-11-17 21 views
13

¿Cuál es la forma adecuada para burlarse y probar el código que devuelve el objeto iters al open(), usando la biblioteca mock?Mocking file objects or 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 

Así es como trato de probarlo.

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

Resultado de python tests.py es:

$ 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: Gracias a Adam, he vuelto a instalar la biblioteca maqueta (pip install -e hg+https://code.google.com/p/mock#egg=mock) y tests.py actualizada. Funciona de maravilla.

Respuesta

15

Está buscando MagicMock. Esto es compatible con la iteración.

En el simulacro 0.80beta4, patch devuelve un MagicMock. Así que este sencillo ejemplo funciona:

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 

Si está ejecutando 0.7.x maqueta (Parece que lo son), no creo que se puede lograr esto con el parche solo. Tendrá que crear la maqueta separado, luego pasarlo en el parche:

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 - Me he encontrado con estos py.test, sin embargo, estos mismos enfoques trabajarán con unittest también.