2010-02-17 5 views
9

У меня есть две функции: одна, которая строит путь к набору файлов, а другая - к чтению файлов. Ниже приведены две функции:Функции тестирования модулей, которые обращаются к файлам

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 

Что было бы лучшим способом для тестирования этих двух функций?

ответ

8

У вас есть две единицы здесь:

  • один, порождающие пути к файлам
  • Second, который читает их

Таким образом, должно быть два юнит-тест-кейсы (т.е. классы с тесты). Сначала будет проверяться только генерация файлов. Во-вторых, будет проверяться чтение из предопределенного набора файлов, которые вы подготовили в специальном подкаталоге каталога тестов, он должен тестироваться изолированно от первого тестового примера.

В вашем случае у вас могут быть очень короткие файлы журналов для тестов. В этом случае для лучшей удобочитаемости и обслуживания рекомендуется вставлять их прямо в тестовый код. Но в этом случае вы будете иметь, чтобы улучшить ваши функции чтения немного, поэтому он может принимать либо имя файла или файл-подобный объект:

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

"... так что это может быть либо имя файла, либо файл-подобный объект" Как это сделать? Проверьте экземпляр str (имя файла), иначе предположите, что это объект ввода-вывода? – Symmitchry

1

Связать имя open в модуле с функцией, которая высмеивает открытие файла.

+0

жалкого совершенно новый. как я могу это сделать? как в насмешливом открытии файла? –

+0

Напишите файл-подобный объект, который реализует различные методы 'file', необходимые вашему коду, а затем просто верните экземпляр из вашей функции' fake_open() '. Импортируйте модуль, затем выполните 'somemodule.open = fake_open'. –

2

Лично я построил тестовый жгут, который настроил необходимые файлы, прежде чем тестировать эти две функции.

Для каждого тестового примера (где вы ожидаете наличия файла - не забудьте также проверить случаи сбоев!), Напишите некоторые известные журналы в файлы с соответствующим именем; затем вызовите проверенные функции и проверьте результаты.

2

Я не эксперт, но я дам ему идти , Сначала немного рефакторинга: сделайте их функциональными (удалите все предметы класса), удалите ненужные вещи. Это должно значительно облегчить тестирование. Вы всегда можете заставить класс вызвать эти функции, если вы действительно хотите его в классе.

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 

Теперь мы можем легко проверить pass_file_name пропускания в пользовательской функции 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 ... 

Как мы предполагаем, os.path.isfile работы мы должны иметь довольно хорошее тестирование первой функции. Хотя вы всегда можете получить тест на самом деле, создайте несколько файлов, затем вызовите pass_file_name с exists = os.path.isfile.

Второе испытание труднее; Мне сказали, что лучшие (единичные) тесты не касаются сети, баз данных, графического интерфейса или жесткого диска. Так что, возможно, некоторые рефакторинги облегчат его работу. Смысл открытия мог бы работать; или бы мог фактически написать какой-нибудь длинный файл в функции тестирования и читать их.

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

Смежные вопросы