Tengo un código fuente que se abre un archivo csv y establece un encabezado para
el valor de la asociación. El código fuente es el siguiente:

def ParseCsvFile(source): 
  """Parse the csv file. 
  Args: 
    source: file to be parsed

  Returns: the list of dictionary entities; each dictionary contains
             attribute to value mapping or its equivalent. 
  """ 
  global rack_file 
  rack_type_file = None 
  try: 
    rack_file = source 
    rack_type_file = open(rack_file)  # Need to mock this line.
    headers = rack_type_file.readline().split(',') 
    length = len(headers) 
    reader = csv.reader(rack_type_file, delimiter=',') 
    attributes_list=[] # list of dictionaries. 
    for line in reader: 
      # More process to happeng. Converting the rack name to sequence. 
      attributes_list.append(dict((headers[i],
                                   line[i]) for i in range(length))) 
    return attributes_list 
  except IOError, (errno, strerror): 
    logging.error("I/O error(%s): %s" % (errno, strerror)) 
  except IndexError, (errno, strerror): 
    logging.error('Index Error(%s), %s' %(errno, strerror)) 
  finally: 
    rack_type_file.close() 

Estoy tratando de burlarse de la siguiente declaración

rack_type_file = open(rack_file) 

¿Cómo burlarse de abrir(…) la función?

  • Me temo que el uso de Burlarse de la biblioteca es un no iniciado. Solo está permitido el uso de mox.
  • Me escribió un ejemplo que utiliza mox para usted.
InformationsquelleAutor Kartik | 2011-03-08

8 Comentarios

  1. 22

    Esta es sin duda una vieja pregunta, por lo tanto algunas de las respuestas son obsoletos.

    En la versión actual de la mock biblioteca hay una función de conveniencia diseñado precisamente para este propósito. He aquí cómo funciona:

    >>> from mock import mock_open
    >>> m = mock_open()
    >>> with patch('__main__.open', m, create=True):
    ...     with open('foo', 'w') as h:
    ...         h.write('some stuff')
    ...
    >>> m.mock_calls
    [call('foo', 'w'),
     call().__enter__(),
     call().write('some stuff'),
     call().__exit__(None, None, None)]
    >>> m.assert_called_once_with('foo', 'w')
    >>> handle = m()
    >>> handle.write.assert_called_once_with('some stuff')

    Documentación es aquí.

    • Por cierto, desde simulacro es ahora parte de la biblioteca estándar, usted puede ahora importar como: from unittest.mock import mock_open.
  2. 13

    Para burlarse de la función integrada abrir con mox uso __builtin__ módulo:

    import __builtin__ # unlike __builtins__ this must be imported
    m = mox.Mox()
    m.StubOutWithMock(__builtin__, 'open')
    open('ftphelp.yml', 'rb').AndReturn(StringIO("fake file content"))     
    m.ReplayAll()
    # call the code you want to test that calls `open`
    m.VerifyAll()
    m.UnsetStubs()

    Nota que __builtins__ no es siempre un módulo, puede ser de tipo dict, por favor, utilice __builtin__ (sin «s») módulo para referirse al sistema integrado de métodos.

    Más acerca de __builtin__ módulo: http://docs.python.org/library/builtin.html

    • gracias, este es exactamente lo que yo estaba buscando. +1 para el uso de mox.
  3. 10

    Hay dos maneras que me gusta hacer esto, dependiendo de la situación.

    Si su unidad de prueba se va a llamar ParseCsvFile directamente me gustaría añadir un nuevo kwarg a ParseCsvFile:

    def ParseCsvFile(source, open=open): 
        # ...
        rack_type_file = open(rack_file)  # Need to mock this line.

    A continuación, la unidad de prueba puede pasar un diferente open_func con el fin de lograr la burla.

    Si su unidad de llamadas de prueba alguna otra función que llama a su vez a ParseCsvFile luego de pasar alrededor de open_func sólo para las pruebas es feo. En ese caso, me gustaría utilizar el simulacro de módulo. Esto le permite alterar una función por su nombre y reemplazarlo con un Simulacro de objeto.

    # code.py
    def open_func(name):
        return open(name)
    
    def ParseCsvFile(source):
        # ...
        rack_type_file = open_func(rack_file)  # Need to mock this line.
    
    # test.py
    import unittest
    import mock
    from StringIO import StringIO
    
    @mock.patch('code.open_func')
    class ParseCsvTest(unittest.TestCase):
        def test_parse(self, open_mock):
            open_mock.return_value = StringIO("my,example,input")
            # ...
    • No necesita llamar a su open reemplazo open_func. Usted puede utilizar open=open en su función de firma y no es necesario realizar ningún (potencialmente ofuscación) cambios en el código.
    • gracias @kindall, editado para incluir tu sugerencia
  4. 4

    Es simple con el decorador (Python3):

    def my_method():
        with open(file="/1.txt", mode='r', encoding='utf-8') as file:
            return file.read().strip()
    
    
    @mock.patch("builtins.open", create=True)
    def test_my_method(mock_open):
        mock_open.side_effect = [
            mock.mock_open(read_data="A").return_value
        ]
    
        resA = my_method()
        assert resA == "A"
    
        mock_open.mock_calls ==  [mock.call(file="/1.txt", mode='r', encoding='utf-8')]
  5. 3

    Me tomé la libertad de re-escribir su función de ejemplo:

    Asumir su función se encuentra en un archivo llamado code.py

    # code.py
    import csv
    
    import logging
    
    
    def ParseCsvFile(source):
        """Parse the csv file.
        Args:
          source: file to be parsed
    
        Returns: the list of dictionary entities; each dictionary contains
                   attribute to value mapping or its equivalent.
        """
        global rack_file
        rack_file = source
        attributes_list = []
    
        try:
            rack_type_file = open(rack_file)
        except IOError, (errno, strerror):
            logging.error("I/O error(%s): %s", errno, strerror)
        else:
            reader = csv.DictReader(rack_type_file, delimiter=',')
            attributes_list = [line for line in reader]   # list of dictionaries
            rack_type_file.close()
    
        return attributes_list

    Un simple caso de prueba sería:

    # your test file
    import __builtin__
    import unittest
    import contextlib
    from StringIO import StringIO
    
    import mox
    
    import code
    
    
    @contextlib.contextmanager
    def mox_replayer(mox_instance):
        mox_instance.ReplayAll()
        yield
        mox_instance.VerifyAll()
    
    
    class TestParseCSVFile(unittest.TestCase):
    
        def setUp(self):
            self.mox = mox.Mox()
    
        def tearDown(self):
            self.mox.UnsetStubs()
    
        def test_parse_csv_file_returns_list_of_dicts(self):
            TEST_FILE_NAME = 'foo.csv'
    
            self.mox.StubOutWithMock(__builtin__, 'open')
            open(TEST_FILE_NAME).AndReturn(StringIO("name,age\nfoo,13"))
    
            with mox_replayer(self.mox):
                result = code.ParseCsvFile(TEST_FILE_NAME)
    
            self.assertEqual(result, [{'age': '13', 'name': 'foo'}])  # works!
    
    
    if __name__ == '__main__':
        unittest.main()

    EDICIÓN:

    % /usr/bin/python2.6
    Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) 
    [GCC 4.2.1 (Apple Inc. build 5646)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import __builtin__
    >>> import mox
    >>> mock = mox.Mox()
    >>> mock.StubOutWithMock(__builtin__, 'open')
    >>> mock.UnsetStubs()

    Funciona bien en 2.6 con el mox 0.53

    • Hola Mahmoud, la solución no funcionó. En su solución, se produce un error en esta línea de auto.mox.StubOutWithMock(builtins, ‘abrir’)
    • ¿qué error con?
    • Hola Mahmoud, la solución no funcionó. Falla en esta línea de auto.mox.StubOutWithMock(builtins, ‘abrir’). builtins es un diccionario. Traté de auto.mox.StubOutWithMox(builtins.get(‘open’), ‘llamada‘ y los métodos indicados a continuación: dir(builtins.get(‘open’)) [‘llamada‘, ‘clase‘, ‘cmp‘, ‘delattr‘, ‘doc‘, ‘eq‘, ‘formato‘, ‘ge‘, ‘getattribute‘, ‘gt‘, ‘hash‘, ‘init‘, ‘archivo‘, ‘lt‘, ‘módulo‘, ‘nombre‘, ‘ne‘, ‘nuevo‘, ‘reducir‘, ‘reduce_ex‘, ‘repr‘, ‘auto‘, ‘setattr‘, ‘tamaño‘, ‘str‘, ‘subclasshook‘]
    • No podía caber en todo en mi comentario anterior. Es el mensaje de error «Archivo» /usr/lib/pymodules/python2.6/mox.py», línea 226, en StubOutWithMock auto.los talones.Set(obj, nombreatributo, stub) File «/usr/lib/pymodules/python2.6/stubout.py», la línea 120, en Conjunto old_attribute = padre.__dict__.get(child_name) AttributeError: ‘builtin_function_or_method’ el objeto no tiene ningún atributo ‘dict
    • builtins no es un diccionario, es un módulo. pegar todo el código aquí: paste.pocoo.org y la respuesta de vuelta con la dirección URL.
    • ¿qué versión de Mox estás usando?
    • paste.pocoo.org/show/352285 he instalado pymox 0.5.3 de google-código de la página web.
    • ¿Por qué estás haciendo auto.mox.StubOutWithMock(builtins.get(‘open’), ‘módulo‘, use_mock_anything=True)? Puede ejecutar el código que he pegado arriba?
    • puede ejecutar estas líneas de código y dime qué es lo que haces en tu máquina? He actualizado mi respuesta.
    • Usted realmente desea el builtin módulo. Lo que ocurre es que builtins se resuelve en la builtin módulo en tu ejemplo, pero no en general. Consulte stackoverflow.com/questions/1184016/…. He modificado el código en consecuencia, a pesar de que veo que Lukas Normantas realmente dio una respuesta correcta a continuación.

  6. 2

    Hola yo estaba teniendo un problema similar, y estaba tirando de los pelos saltando entre diferentes burlándose de las bibliotecas. Finalmente encontré una solución que estoy contento con el, y tal vez te podría ayudar? Al final me fui con la Mocker biblioteca http://labix.org/mocker y aquí está el código para burlarse de abrir:

    from mocker import Mocker
    from StringIO import StringIO
    import __builtin__
    mocker = Mocker()
    sourceFile = 'myTestFile.txt'
    __builtin__.open = mocker.mock()
    __builtin__.open(sourceFile)
    mocker.result(StringIO('this,is,a,test,file'))
    
    <the rest of your test setup goes here>
    
    mocker.replay()
    
    ParseCsvFile(sourceFile)
    
    mocker.restore()
    mocker.verify()

    Incidentaly la razón por la que fui con Mocker es porque estaba probando una función que utiliza abierto para leer un archivo y, a continuación, utiliza de nuevo abierta para sobrescribir el mismo archivo con los nuevos datos. Lo que yo necesitaba para ser capaz de hacer era probar el caso en que el archivo inicial no existía, por lo que establecen un simulacro, que lanzó una excepción IOError la primera vez, y luego trabajó en el segundo tiempo. La instalación para la que se veía así:

    from mocker import Mocker
    import __builtin__
    
    mocker = Mocker()
    
    mockFileObject = mocker.mock()
    __builtin__.open = mocker.mock()
    
    __builtin__.open('previousState.pkl', 'r') 
    mocker.throw(IOError('Boom'))
    
    __builtin__.open('previousState.pkl','w') 
    mocker.result(mockFileObject)
    
    <rest of test setup >
    
    mocker.replay()
    
    <test>
    
    mocker.restore() #required to restore the open method
    mocker.verify()

    Espero que esto ayude!

  7. 1

    @mock.parche decorador (2.7 ejemplo)

    Esto es ahora mucho más fácil:

    import your_script.py
    import __builtin__
    import mock
    
    
    @mock.patch("__builtin__.open")
    def test_example(self, mock_open):
        your_script.your_method()
        self.assertEqual(mock_open.call_count, 1)
  8. 0
    >>> class A(object):
    ...     def __init__(self):
    ...         self.x = open('test.py')
    ... 
    >>> old_open = open
    >>> def open(s):
    ...     return "test\n"
    ... 
    >>> a = A()
    >>> a.x
    'test\n'
    >>> open = old_open
    >>> a = A()
    >>> a.x
    <open file 'test.py', mode 'r' at 0xb7736230>

Dejar respuesta

Please enter your comment!
Please enter your name here