Запускаем тестирование

zapuskaem testirovanie Законченные системные программы

Основная магия сценария, выполняющего тестирование, представленного в примере 6.9, заключена в используемой им структуре каталогов. При первом запуске в каталоге тестирования (или если вы заставляете его начать сначала, передавая ему второй аргумент командной строки) сценарий:

     Составит список тестируемых сценариев в подкаталоге Scripts

     Извлечет ассоциированные с тестируемым сценарием входной файл и аргументы командной строки из подкаталогов Inputs и Args

     Сгенерирует начальные файлы для стандартного потока вывода stdout, которые обычно помещаются в подкаталог Outputs

     Сообщит о сценариях, в процессе тестирования которых либо появились сообщения об ошибках в потоке stderr, либо код завершения отличается от нуля

В случае любых ошибок, обнаруженных при тестировании сценария, сохраняется содержимое потока stderr с текстом сообщений об ошибках, а также полный вывод, сгенерированный до момента ошибки. Текст из стандартного потока ошибок сохраняется в файл в подкаталоге Errors. Содержимое стандартного вывода в случае обнаружения ошибок сохраняется в файл, имя которого имеет специальное расширение «.bad» в подкаталоге Outputs (сохранение в файле с нормальным именем в подкаталоге Outputs привело бы к ошибке тестирования после устранения ошибки в тестируемом сценарии!). Ниже приводится пример первого запуска:

C:\\PP4E\System\Tester> python tester.py . 1

Start tester: Mon Feb 22 22:13:38 2010

in C:\Users\mark\Stuff\Books\4E\PP4E\dev\Examples\PP4E\System\Tester

generating: .\Outputs\test-basic-args.out

generating: .\Outputs\test-basic-stdout.out

generating: .\Outputs\test-basic-streams.out

generating: .\Outputs\test-basic-this.out

ERROR status: test-errors-runtime.py 1

ERROR stream: test-errors-runtime.py .\Errors\test-errors-runtime.err

ERROR status: test-errors-syntax.py 1

ERROR stream: test-errors-syntax.py .\Errors\test-errors-syntax.err

ERROR status: test-status-bad.py 42

generating: .\Outputs\test-status-good.out

Finished: Mon Feb 22 22:13:41 2010

8 tests were run, 3 tests failed.

При запуске каждого сценария тестирующий сценарий устанавливает все заданные аргументы командной строки, передает все входные данные (если таковые имеются) в канал ввода и перехватывает стандартные потоки вывода и ошибок, сохраняет код завершения. Когда я запускал этот пример, в каталоге находилось 8 тестируемых сценариев, а также множество входных и выходных файлов. Поскольку схема именования каталогов и файлов имеет ключевое значение для данного примера, ниже приводится список с содержимым тестового каталога для этого сеанса — основным является каталог Scripts, потому что в нем собраны тестируемые сценарии:

C:\\PP4E\System\Tester> dir /B

Args

Errors

Inputs

Outputs

Scripts

tester.py xxold

C:\\PP4E\System\Tester> dir /B Scripts

test-basic-args.py

test-basic-stdout.py

test-basic-streams.py

test-basic-this.py

test-errors-runtime.py

test-errors-syntax.py

test-status-bad.py

test-status-good.py

Другие подкаталоги содержат все необходимые входные данные и выходные файлы с результатами работы тестируемых сценариев:

C:\\PP4E\System\Tester> dir /B Args

test-basic-args.args test-status-good.args

C:\\PP4E\System\Tester> dir /B Inputs

test-basic-args.in

test-basic-streams.in

C:\\PP4E\System\Tester> dir /B Outputs

test-basic-args.out

test-basic-stdout.out

test-basic-streams.out

test-basic-this.out

test-errors-runtime.out.bad

test-errors-syntax.out.bad test-status-bad.out.bad test-status-good.out

C:\\PP4E\System\Tester> dir /B Errors

test-errors-runtime.err

test-errors-syntax.err

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

C:\\PP4E\System\Tester> type Scripts\test-basic-args.py

подпись: # в outputsподпись: # из args
# в outputs
подпись: # в outputs # из inputs # из inputs # в outputs# аргументы, потоки import sys, os print(os.getcwd()) print(sys.path[0]) print(‘[argv]’)

for arg in sys.argv print(arg)

print(‘[interaction]’)

text = input(‘Enter text:’) rept = sys.stdin.readline() sys.stdout.write(text * int(rept))

C:\\PP4E\System\Tester> type Args\test-basic-args.args -command -line stuff

C:\\PP4E\System\Tester> type Inputs\test-basic-args.in Eggs 10

C:\\PP4E\System\Tester> type Outputs\test-basic-args.out

C:\Users\mark\Stuff\Books\4E\PP4E\dev\Examples\PP4E\System\Tester

C:\Users\mark\Stuff\Books\4E\PP4E\dev\Examples\PP4E\System\Tester\Scripts [argv]

.\Scripts\test-basic-args.py

-command

-line

stuff

[interaction]

Enter text:EggsEggsEggsEggsEggsEggsEggsEggsEggsEggs

А еще ниже — два файла, связанные с одной из обнаруженных ошибок. Первый из них хранит содержимое потока stderr, а второй — содержимое потока stdout, сгенерированное до момента появления ошибки. Они предназначены для анализа человеком (или с помощью других инструментов) и автоматически будут удалены в следующем сеансе тестирования:

C:\\PP4E\System\Tester> type Errors\test-errors-runtime.err

Traceback (most recent call last):

File “.\Scripts\test-errors-runtime.py”, line 3, in <module>

print(1 / 0)

ZeroDivisionError: int division or modulo by zero

C:\\PP4E\System\Tester> type Outputs\test-errors-runtime.out.bad starting

Если теперь запустить тестирование еще раз, не внося никаких изменений в тестируемые сценарии, тестирующий сценарий сравнит сохраненные ранее результаты с новыми и определит отсутствие регрессий. Об ошибках, которые определяются по коду завершения, и о наличии сообщений в потоке stderr будет сообщаться, как и прежде, но в других тестах не будет обнаружено никаких отклонений от сохраненных ранее результатов:

C:\\PP4E\System\Tester> python tester.py

Start tester: Mon Feb 22 22:26:41 2010

in C:\Users\mark\Stuff\Books\4E\PP4E\dev\Examples\PP4E\System\Tester

passed: test-basic-args.py

passed: test-basic-stdout.py

passed: test-basic-streams.py

passed: test-basic-this.py

ERROR status: test-errors-runtime.py 1

ERROR stream: test-errors-runtime.py .\Errors\test-errors-runtime.err

ERROR status: test-errors-syntax.py 1

ERROR stream: test-errors-syntax.py .\Errors\test-errors-syntax.err

ERROR status: test-status-bad.py 42

passed: test-status-good.py

Finished: Mon Feb 22 22:26:43 2010

8 tests were run, 3 tests failed.

Но когда я внес в один из тестируемых сценариев изменение, повлиявшее на его вывод (я изменил счетчик цикла, чтобы сценарий выводил меньше строк), тестирующий сценарий обнаружил регрессию и сообщил о ней — отличия между новым и старым выводом были восприняты как ошибка прохождения теста, и новый вывод был сохранен в подкаталоге Outputs в файле с расширением «.bad»:

C:\\PP4E\System\Tester> python tester.py

Start tester: Mon Feb 22 22:28:35 2010

in C:\Users\mark\Stuff\Books\4E\PP4E\dev\Examples\PP4E\System\Tester passed: test-basic-args.py

FAILED output: test-basic-stdout.py .\Outputs\test-basic-stdout.out.bad passed: test-basic-streams.py passed: test-basic-this.py

ERROR status: test-errors-runtime.py 1

ERROR stream: test-errors-runtime.py .\Errors\test-errors-runtime.err

ERROR status: test-errors-syntax.py 1

ERROR stream: test-errors-syntax.py .\Errors\test-errors-syntax.err

ERROR status: test-status-bad.py 42

passed: test-status-good.py

Finished: Mon Feb 22 22:28:38 2010

8 tests were run, 4 tests failed.

C:\\PP4E\System\Tester> type Outputs\test-basic-stdout.out.bad begin

Spam!

Spam!Spam!

Spam!Spam!Spam!

Spam!Spam!Spam!Spam!

end

И еще одно замечание по использованию: если переменную trace в этом сценарии установить в значение verbose, он будет выводить более подробные сообщения, которые помогут вам проследить за порядком выполнения программы (но, вероятно, чересчур подробные для практического применения):

C:\\PP4E\System\Tester> tester.py

Start tester: Mon Feb 22 22:34:51 2010

in C:\Users\mark\Stuff\Books\4E\PP4E\dev\Examples\PP4E\System\Tester

C:\Users\mark\Stuff\Books\4E\PP4E\dev\Examples\PP4E\System\Tester

.\Scripts\test-basic-args.py

.\Scripts\test-basic-stdout.py

.\Scripts\test-basic-streams.py

.\Scripts\test-basic-this.py

.\Scripts\test-errors-runtime.py

.\Scripts\test-errors-syntax.py

.\Scripts\test-status-bad.py .\Scripts\test-status-good.py

C:\Python31\python.exe .\Scripts\test-basic-args.py -command -line stuff b’Eggs\r\n10\r\n’ b’C:\\Users\\mark\\Stuff\\Books\\4E\\PP4E\\dev\\Examples\\PP4E\\System\\Tester\r \nC:\\Users\\mark\\Stuff\\Books\\4E\\PP4E\\dev\\Examples\\PP4E\\System\\Tester\\ Scripts\r\n[argv]\r\n.\\Scripts\\test-basic-args.py\r\n-command\r\n-line\r\nst uff\r\n[interaction]\r\nEnter text:EggsEggsEggsEggsEggsEggsEggsEggsEggsEggs’ b’’

0

passed: testbasicargs.py

…множество строк удалено…

Изучите внимательнее реализацию тестирующего сценария, чтобы получить о нем более полное представление. Естественно, о тестировании как таковом можно было бы рассказать намного больше, чем позволяет пространство книги. Например, для тестирования сценариев необязательно запускать их в дочерних процессах и вполне можно обойтись импортированием модулей и тестированием с помощью обработчиков исключений в инструкциях try. Кроме того, наш тестирующий сценарий можно было бы расширять и совершенствовать в самых разных направлениях (некоторые предложения приводятся в строке документирования). Более того, в состав Python входят два фреймворка тестирования, doctest и unittest (он же PyUnit), которые предоставляют инструменты и структуры для создания регрессивных и модульных тестов:

unittest

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

doctest

Анализирует и выполняет тесты, представленные в виде листингов интерактивного сеанса в строках документирования внутри тестируемого модуля. В листингах определяются тестовые вызовы и ожидаемые результаты — фреймворк doctest по сути повторно выполняет интерактивный сеанс.

За дополнительной информацией об инструментах и способах тестирования, сторонних или входящих в состав Python, обращайтесь к руководству по библиотеке Python, на веб-сайт PyPI и к своим любимым поисковым системам.

Тем не менее наш сценарий прекрасно справляется с задачей автоматизации тестирования сценариев командной строки на языке Python, которые выполняются как независимые программы в стандартном контексте выполнения. Поскольку наш сценарий полностью независим от тестируемых сценариев, мы можем определять новые совокупности тестовых данных без необходимости изменять реализацию тестирующего сценария. А так как он написан на языке Python, его легко и быстро можно приспосабливать под новые потребности. Как мы увидим еще раз в следующем разделе, такая простота, обеспечиваемая языком Python, может оказаться решающим преимуществом для реальных задач.

Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011

Оцените статью
Секреты программирования
Добавить комментарий