Надлежащий способ организовать тестовые случаи, которые включают файл данных для каждого тестового случая? - PullRequest
7 голосов
/ 17 августа 2011

Я пишу модуль, который включает в себя анализ HTML для данных и создание объекта из них. По сути, я хочу создать набор тестовых случаев, где каждый случай представляет собой HTML-файл в паре с золотым / ожидаемым маринованным объектным файлом.

При внесении изменений в синтаксический анализатор я хотел бы запустить этот набор тестов, чтобы убедиться, что каждая html-страница анализируется так, чтобы она соответствовала «золотому» файлу (по сути, набору регрессий)

Я вижу, как закодировать это как один контрольный пример, где я загружаю все пары файлов из некоторого каталога, а затем перебираю их. Но я полагаю, что в итоге это будет представлено как один тестовый сценарий, пройденный или неудачный. Но мне нужен отчет, в котором говорится, например, что 45/47 страниц успешно проанализировано.

Как мне это устроить?

Ответы [ 2 ]

4 голосов
/ 17 августа 2011

Я сделал аналогичные вещи с unittest фреймворком, написав функцию, которая создает и возвращает тестовый класс. Затем эта функция может принимать любые параметры и настраивать тестовый класс соответствующим образом. Вы также можете настроить атрибут __doc__ тестовых функций для получения настраиваемых сообщений при выполнении тестов.

Я быстро набрал следующий пример кода, чтобы проиллюстрировать это. Вместо того, чтобы проводить какое-либо реальное тестирование, он использует модуль random, чтобы провалить некоторые тесты в демонстрационных целях. При создании классы вставляются в глобальное пространство имен, так что вызов unittest.main() подхватит их. В зависимости от того, как вы выполняете свои тесты, вы можете захотеть сделать что-то другое с сгенерированными классами.

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

Пример прогона:

$ 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 голосов
/ 17 августа 2011

Фреймворк для тестирования носа поддерживает это.http://www.somethingaboutorange.com/mrl/projects/nose/

Также см. Здесь: Как генерировать динамические (параметризованные) модульные тесты в python?

Вот что я хотел бы сделать (не проверено):

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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...