Часть 2. log viewer tests: Масло масляное :-)


А пишите ли Вы тесты к Вашим тестам?

С одной стороны это:
  • повышает надёжность самой тестовой системы;
  • заставляет писать код лучше;
  • и просто, круто!

С другой стороны:
  • несколько избыточно;
  • требует времени.

До этого эксперимерта, к идеи написания тестов к тестовому фреймворку я относился скептически. А сейчас (после их написания) мне эта идея всё больше нравится... Это заставило меня довольно сильно изменить изначальный код - в лучшую сторону.

А вот  давайте таки напишем тесты к предыдущему модулю - logViewer!

Итак, будем использовать стандартный unittest для питона.

Самый простой способ запуска - через CLI:
python testLogViewer.py

При этом результаты будут выходить в таком виде:
yuriy@yuriys:/warehouse/projects/dreamFramework/src/logViewer/test$ python testLogViewer.py 
.........
----------------------------------------------------------------------
Ran 9 tests in 41.646s

А реализованно всё это так:

1. Есть один файл, в котором собраны все тесты - testLogViewer.py:

Для каждой однотипной группы тестов создаётся класс с набором тестовых методов. Например:
class TestLogViewerBase(LogViewerTestBase):
""" """
def testSimple(self):
""" """
testString = "bla bla ERROR du du du"


# emulate entering some data to log file
self._addString(testString)


# lets give some time for logViewer to wake up and check data
time.sleep(timeforWaitingLogwatcher)


# get captured data
logMessagesForCurrentTestAndFile = self.getLogMessagesForCurrentTest()


# assert captured data
if logMessagesForCurrentTestAndFile.has_key(self._tagNames):
logMessages = logMessagesForCurrentTestAndFile[self._tagNames]
if logMessages and (1 == len(logMessages)):
self.assertTrue(testString == logMessages[0], "Oops! Can't find log message ('" + testString + "')!..")
else:
self.fail("Oops! Log entry is not captured at all!..")
else:
self.fail("Oops! Neccessary log entry is not captured!..")


2. Далее есть набор классов в которых переопределяются некоторые методы классы LogViewerTestBase, который в свою очередь создаёт:
  • файлы логов, которые будут использоваться во время тестирования;
  • класс LogViewManager cо специфическими параметрами.


Вот эти классы:
  • LogViewerTestFileDelay
  • LogViewerTestIgnore
  • LogViewerTestWithOutFile
  • LogViewerTestWithTwoFiles


Например, logViewerTestWithTwoFiles.py:

Этот класс организует проверку того, как два лога обрабатываются одновременно:
class LogViewerTestWithTwoFiles(LogViewerTestBase):
""" Check log viewer processing situation when log file is absent... """


def __init__(self, methodName='runTest'):
""" """
LogViewerTestBase.__init__(self, methodName)
self._logFile4Test2 = "./data/test2.log"


def setUp(self):
""" Create second file and, then, default setup """
self._createTestLogFile(self._logFile4Test2)
LogViewerTestBase.setUp(self)


def tearDown(self):
""" Clean default test environment and second file """
LogViewerTestBase.tearDown(self)
self._removeTestLogFile(self._logFile4Test2)


def _startLogViewManager(self):
""" Start LogViewerManager with test parameters - with special log file and tag for watching """
self._logViewerManager = LogViewerManager([self._logFile4Test, self._logFile4Test2], [self._tagNames])
self._logViewerManager.testBegin(self._testName4LogViewer)

3. Есть отдельный файл с параметрами, которые используют тесты - logViewerTestProperties.py
Сейчас там такие пераметры:
  • время, котрые мы даём фреймворку на обнаружение новой записи в логе;
  • настройка лога (да, да! лога тестов, которые тестируют то, как анализируются логи :-)).


Вот диаграмма классов:

Исходники на sourceforge.net

P.S. Мне кажется, что тесты получились ни чуть не проще, чем тестируемая система... Ну, что ж вот такая у нас работа!