2010-02-17 6 views
9

Tengo dos funciones: una que crea la ruta a un conjunto de archivos y otra que lee los archivos. Debajo están las dos funciones:Funciones de prueba de unidad que tienen acceso a los archivos

def pass_file_name(self): 
    self.log_files= [] 
    file_name = self.path+"\\access_"+self.appliacation+".log" 
    if os.path.isfile(file_name): 
     self.log_files.append(file_name) 
    for i in xrange(7): 
     file_name = self.path+"\\access_"+self.appliacation+".log"+"."+str(i+1) 
     if os.path.isfile(file_name): 
      self.log_files.append(file_name) 
    return self.log_files 


def read_log_files (self, log_file_names): 
    self.log_entrys = [] 
    self.log_line = [] 
    for i in log_file_names: 
     self.f = open(i) 
     for line in self.f: 
      self.log_line = line.split(" ") 
      #print self.log_line 
      self.log_entrys.append(self.log_line) 
    return self.log_entrys 

¿Cuál sería la mejor manera de probar estas dos funciones?

Respuesta

8

Tiene dos unidades aquí:

  • Uno que generan rutas de archivos
  • segundo que los lee

lo tanto no debe haber dos unidades de los ensayos de los casos (es decir, las clases con pruebas). Primero probaría solo la generación de rutas de archivos. En segundo lugar, probaría la lectura del conjunto predefinido de archivos que preparó en el subdirectorio especial del directorio de pruebas, debe probarse aisladamente desde el primer caso de prueba.

En su caso, probablemente podría tener archivos de registro muy cortos para las pruebas. En este caso, para una mejor legibilidad y mantenimiento, es una buena idea incluirlos en el código de prueba. Pero en este caso tendrá que mejorar su función de lectura un poco para que pueda tomar o nombre de archivo o tipo fichero objeto:

from cStringIO import StringIO 

# ... 
def test_some_log_reading_scenario(self): 
    log1 = '\n'.join([ 
     'log line', 
     'another log line' 
    ]) 
    log2 = '\n'.join([ 
     'another log another line', 
     'lala blah blah' 
    ]) 
    # ... 
    result = myobj.read_log_files([StringIO(log1), StringIO(log2)]) 
    # assert result 
+1

"... para que pueda tomar el nombre del archivo o el objeto similar a un archivo" ¿Cómo hago eso? Compruebe por ejemplo de str (un nombre de archivo), de lo contrario, suponga que es un objeto IO? – Symmitchry

1

Enlaza el nombre open en el módulo con una función que se burla de la apertura del archivo.

+0

siento totalmente nuevo aquí. ¿Cómo hago eso? como en la apertura de archivos burlones? –

+0

Escriba un objeto similar a un archivo que implemente los diversos métodos de 'archivo' requeridos por su código, luego simplemente devuelva una instancia desde su función 'fake_open()'. Importa el módulo y luego haz 'somemodule.open = fake_open'. –

2

Personalmente, construiría un arnés de prueba que configuraría los archivos necesarios antes de probar esas dos funciones.

Para cada caso de prueba (donde espera que el archivo esté presente, recuerde probar los casos de error también), escriba algunos registros conocidos en los archivos apropiadamente nombrados; luego llame a las funciones bajo prueba y verifique los resultados.

2

No soy un experto pero voy a darle una oportunidad . Primero un poco de refactorización: hacerlos funcionales (eliminar todo lo de la clase), eliminar cosas innecesarias. Esto debería hacer que sea mucho más fácil de probar. Siempre puede hacer que la clase llame a estas funciones si realmente lo desea en una clase.

def pass_file_name(base_filename, exists): 
    """return a list of filenames that exist 
     based upon `base_filename`. 
     use `os.path.isfile` for `exists`""" 

    log_files = [] 
    if exists(base_filename): 
     log_files.append(base_filename) 
    for i in range(1, 8): 
     filename = base_filename + "." + str(i) 
     if exists(filename): 
      log_files.append(filename) 
    return log_files 

def read_log_files (self, log_files): 
    """read and parse each line from log_files 
     use `pass_file_name` for `log_files`""" 

    log_entrys = [] 
    for filename in log_files: 
     with open(filename) as myfile: 
      for line in myfile: 
       log_entrys.append(line.split()) 
    return log_entrys 

Ahora podemos probar fácilmente pass_file_name mediante introducción de una función personalizada para exists.

class Test_pass_file_name(unittest.TestCase): 
    def test_1(self): 
     """assume every file exists 
      make sure all logs file are there""" 
     exists = lambda _: True 
     log_files = pass_file_name("a", exists) 
     self.assertEqual(log_files, 
        ["a", "a.1", "a.2", "a.3", 
        "a.4", "a.5", "a.6", "a.7"]) 

    def test_2(self): 
     """assume no files exists 
      make sure nothing returned""" 
     exists = lambda _: False 
     log_files = pass_file_name("a", exists) 
     self.assertEqual(log_files, []) 

    # ...more tests here ... 

Como suponemos os.path.isfile obras que debería haber conseguido bastante bien las pruebas de la primera función. Aunque siempre puede hacer que la prueba cree realmente algunos archivos, llame al pass_file_name con exists = os.path.isfile.

El segundo es más difícil de probar; Me han dicho que las mejores pruebas (de unidad) no tocan la red, las bases de datos, la GUI o el disco duro. Así que tal vez un poco más de refactorización lo haría más fácil. La burla abierta podría funcionar; o que en realidad podría escribir algún archivo largo en la función de prueba y leerlos en.

How do I mock an open used in a with statement (using the Mock framework in Python)?

Cuestiones relacionadas