А пишите ли Вы тесты к Вашим тестам?
С одной стороны это:
- повышает надёжность самой тестовой системы;
- заставляет писать код лучше;
- и просто, круто!
С другой стороны:
- несколько избыточно;
- требует времени.
До этого эксперимерта, к идеи написания тестов к тестовому фреймворку я относился скептически. А сейчас (после их написания) мне эта идея всё больше нравится... Это заставило меня довольно сильно изменить изначальный код - в лучшую сторону.
А вот давайте таки напишем тесты к предыдущему модулю - 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. Мне кажется, что тесты получились ни чуть не проще, чем тестируемая система... Ну, что ж вот такая у нас работа!
