А пишите ли Вы тесты к Вашим тестам?
Масло маслянное :-)
Как вы помните, мы реализовали первую подсистему тествого фреймворка, и есть предложение, прежде, чем браться за следующую, закрепить успех - протестировать саму тестовую систему... И, сделать так, чтобы она оставалась стабильной и при последующих модификациях.
Давайте напишем тесты!
С одной стороны это:
- повышает надёжность самой тестовой системы
- заставляет писать код лучше
- и просто, круто!
С другой стороны:
- несколько избыточно
- требует времени
До этого эксперимента к идеи написания тестов к тестовому фреймворку я относился скептически. А сейчас (после их написания) мне эта идея всё больше нравится... Это заставило меня довольно сильно изменить изначальный код - в лучшую сторону.
Итак, будем использовать стандартный unittest для Питона.
Самый простой способ запуска - через CLI:
{syntaxhighlighter brush: bash;light: true; fontsize: 100; first-line: 1; }python testLogViewer.py{/syntaxhighlighter}
При этом результаты будут выходить в таком виде:
{syntaxhighlighter brush: bash;light: true; fontsize: 100; first-line: 1; }yuriy@yuriys:/warehouse/projects/dreamFramework/src/logViewer/test$ python testLogViewer.py ......... ---------------------------------------------------------------------- Ran 9 tests in 41.646s{/syntaxhighlighter}
А реализовано всё это так:
1. Есть один файл, в котором собраны все тесты - testLogViewer.py:
Для каждой однотипной группы тестов создаётся класс с набором тестовых методов. Например:
{syntaxhighlighter brush: python;light: true; fontsize: 100; first-line: 1; }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!.."){/syntaxhighlighter}</p><p><br>2. Далее есть набор классов, в которых переопределяются некоторые методы класса <strong>LogViewerTestBase</strong>, который в свою очередь создаёт:</p><ul><li>файлы логов, которые будут использоваться во время тестирования</li><li>класс LogViewManager cо специфическими параметрами</li></ul><p style="text-align: left;">Вот эти классы:</p><ul><li>LogViewerTestFileDelay</li><li>LogViewerTestIgnore</li><li>LogViewerTestWithOutFile</li><li>LogViewerTestWithTwoFiles</li></ul><p style="text-align: left;">Например, <strong>logViewerTestWithTwoFiles.py</strong>:<br><br>Этот класс организует проверку того, как два лога обрабатываются одновременно:</p><p>{syntaxhighlighter brush: python;light: true; fontsize: 100; first-line: 1; }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){/syntaxhighlighter}</p><p><br>3. Есть отдельный файл с параметрами, которые используют тесты - <strong>logViewerTestProperties.py</strong><br>Сейчас там такие пераметры:</p><ul><li>время, которое мы даём фреймворку на обнаружение новой записи в логе</li><li>настройка лога (да, да! лога тестов, которые тестируют то, как анализируются логи :-))</li></ul><p style="text-align: left;"><br>Вот диаграмма классов:<br><img src="http://2.bp.blogspot.com/_XFzJwPAOQgU/TDOuA5O1JTI/AAAAAAAAFwc/Nn_0FgF8t3g/s1600/logViewerTest+class+diagram.png" alt="logViewerTest class diagram" title="logViewerTest class diagram" width="704" height="395" class="mceItem"></p><p style="text-align: left;">P.S. Мне кажется, что тесты получились ни чуть не проще, чем тестируемая система... Ну, что ж вот <a href="http://www.sovmusic.ru/text.php?fname=ourduty" target="_blank">такая у нас работа!</a></p>