2011-08-16 14 views
7

Sto scrivendo un modulo che comporta l'analisi di html per i dati e la creazione di un oggetto da esso. Fondamentalmente, voglio creare una serie di test in cui ogni caso è un file html accoppiato con un file oggetto dorato/previsto in salamoia.Modo corretto per organizzare i test che coinvolgono un file di dati per ogni testcase?

Come posso apportare modifiche al parser, vorrei eseguire questo suite di test per garantire che ogni pagina html viene analizzato per eguagliare il file 'd'oro' (essenzialmente una suite di regressione)

posso vedere come codice questo come un singolo test case, dove vorrei caricare tutte le coppie di file da qualche directory e poi scorrere attraverso di loro. Ma credo che questo finirebbe per essere segnalato come un singolo test, passare o fallire. Ma voglio un rapporto che dice, ad esempio, 45/47 pagine analizzate con successo.

Come si organizza?

risposta

3

Ho fatto cose simili con il quadro unittest scrivendo una funzione che crea e restituisce un test classe. Questa funzione può quindi accettare i parametri desiderati e personalizzare la classe di test di conseguenza. È inoltre possibile personalizzare l'attributo __doc__ delle funzioni di test per ottenere messaggi personalizzati durante l'esecuzione dei test.

Ho rapidamente ribaltato il seguente codice di esempio per illustrare questo. Invece di eseguire test effettivi, utilizza il modulo random per non riuscire alcuni test a scopo dimostrativo. Quando vengono create, le classi vengono inserite nello spazio dei nomi globale in modo che una chiamata a unittest.main() le prelevi. A seconda di come esegui i test, potresti voler fare qualcosa di diverso con le classi generate.

import os 
import unittest 

# Generate a test class for an individual file. 
def make_test(filename): 
    class TestClass(unittest.TestCase): 
     def test_file(self): 
      # Do the actual testing here. 
      # parsed = do_my_parsing(filename) 
      # golden = load_golden(filename) 
      # self.assertEquals(parsed, golden, 'Parsing failed.') 

      # Randomly fail some tests. 
      import random 
      if not random.randint(0, 10): 
       self.assertEquals(0, 1, 'Parsing failed.') 

     # Set the docstring so we get nice test messages. 
     test_file.__doc__ = 'Test parsing of %s' % filename 

    return TestClass 

# Create a single file test. 
Test1 = make_test('file1.html') 

# Create several tests from a list. 
for i in range(2, 5): 
    globals()['Test%d' % i] = make_test('file%d.html' % i) 

# Create them from a directory listing. 
for dirname, subdirs, filenames in os.walk('tests'): 
    for f in filenames: 
     globals()['Test%s' % f] = make_test('%s/%s' % (dirname, f)) 

# If this file is being run, run all the tests. 
if __name__ == '__main__': 
    unittest.main() 

Un esempio di esecuzione:

$ python tests.py -v 
Test parsing of file1.html ... ok 
Test parsing of file2.html ... ok 
Test parsing of file3.html ... ok 
Test parsing of file4.html ... ok 
Test parsing of tests/file5.html ... ok 
Test parsing of tests/file6.html ... FAIL 
Test parsing of tests/file7.html ... ok 
Test parsing of tests/file8.html ... ok 

====================================================================== 
FAIL: Test parsing of tests/file6.html 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "generic.py", line 16, in test_file 
    self.assertEquals(0, 1, 'Parsing failed.') 
AssertionError: Parsing failed. 

---------------------------------------------------------------------- 
Ran 8 tests in 0.004s 

FAILED (failures=1) 
3

Il framework di test del naso supporta questo. http://www.somethingaboutorange.com/mrl/projects/nose/

vedi anche qui: How to generate dynamic (parametrized) unit tests in python?

Ecco cosa farei (non testata):

files = os.listdir("/path/to/dir") 

class SomeTests(unittest.TestCase): 

    def _compare_files(self, file_name): 
     with open('/path/to/dir/%s-golden' % file_name, 'r') as golden: 
      with open('/path/to/dir/%s-trial' % file_name, 'r') as trial:  
       assert golden.read() == trial.read()  


def test_generator(file_name): 
    def test(self): 
     self._compare_files(file_name): 
    return test 

if __name__ == '__main__': 
    for file_name in files: 
     test_name = 'test_%s' % file_name 
     test = test_generator(file_name) 
     setattr(SomeTests, test_name, test) 
    unittest.main() 
+0

Beh, ovviamente, ho potuto farlo ... ma qualsiasi soluzione decente non dovrebbe hardcode il numero/nome di file/testcases. Dovrebbe caricare tutto ciò che è in una directory, o lista file, ecc. – Ian

+0

Aggiornato per utilità. – nottombrown

+0

molto meglio. Grazie! – Ian

Problemi correlati