Разделение stdout и stderr в python nosetest
Проблема: в python есть популярный xUnit фреймворк nose, которым пользуются довольно много людей. Когда подключаешь nose к continuous integration, то хочешь чтобы результаты были максимально видимыми и репрезентативными. Но вот есть одна проблема, всю выходную информацию nose записывает в один поток, либо stdout либо stderr. А как же быть, если нам нужно показать часть в stderr, а часть в stdout?
Например
Результат прогона полностью выводиться в stderr:
#1 Test 1 … ok
#2 Test 2 … FAIL
#3 Test 3 … ok
#4 Test 4 … ok
#5 Test 5 … FAIL
==============================
FAIL: Test 2
——————————
Traceback (most recent call last):
File “/home/katerina/Desktop/my_
self.assertEquals(1, 2)
AssertionError: 1 != 2
==============================
FAIL: Test 5
——————————
Traceback (most recent call last):
File “/home/katerina/Desktop/my_
self.assertEquals(1, 7)
AssertionError: 1 != 7
——————————
XML: nosetests.xml
——————————
Ran 5 tests in 0.004s
FAILED (failures=2)
А надо чтоб результат выводился в 2 потока:
#1 Test 1 … ok
#2 Test 2 … FAIL
#3 Test 3 … ok
#4 Test 4 … ok
#5 Test 5 … FAIL
==============================
FAIL: Test 2
——————————
Traceback (most recent call last):
File “/home/katerina/Desktop/my_
self.assertEquals(1, 2)
AssertionError: 1 != 2
==============================
FAIL: Test 5
——————————
Traceback (most recent call last):
File “/home/katerina/Desktop/my_
self.assertEquals(1, 7)
AssertionError: 1 != 7
——————————
XML: nosetests.xml
——————————
Ran 5 tests in 0.004s
FAILED (failures=2)
Вся соль в том, что nose основывает весь свой запуск на unittest. А в unittest используется механизм буферизации stdout и stderr, т.е. unittest все ловит, но в последствии все уходит в один поток. Этот поток по умолчанию stderr. Его конечно можно поменять, но все равно это запись содержимого прогона в один поток или stderr или stdout.
Решение: простое решение – это переопределить TextTestResult и TextTestRunner при запуске тестов. Смотрим пример:
import unittest import sys import nose from nose.core import TextTestRunner from nose.result import TextTestResult from cStringIO import StringIO class Tests(unittest.TestCase): def test_1(self): """Test 1""" print 'something' self.assertEquals(1, 1) def test_2(self): """Test 2""" self.assertEquals(1, 1) def test_3(self): """Test 3""" self.assertEquals(1, 1) def test_4(self): """Test 4""" self.assertEquals(1, 1) def test_5(self): """Test 5""" print 'something' raise AssertionError("error") self.assertEquals(1, 1) if __name__ == '__main__': class MyTextTestResult(TextTestResult): def addError(self, test, err): print >> sys.stderr, "%r ... error\n\t%r" % (test, err) def addFailure(self, test, err): print >> sys.stderr, "%r ... failure\n\t%r" % (test, err) def addSuccess(self, test): print >> sys.stdout, "%r ... ok" % test class MyTextTestRunner(TextTestRunner): def __init__(self): TextTestRunner.__init__(self, stream=StringIO()) def _makeResult(self): return MyTextTestResult(self.stream, self.descriptions, self.verbosity, self.config) nose.main(testRunner=MyTextTestRunner())
Пример можно скачать здесь https://github.com/polusok/nose-split-stderr-stdout. Это далеко не идеальное решение, но позволит Вам быстро решить вашу задачу.
Успехов и хорошего питонирования!
З.Ы. С 05.08 стартует следующая группа по обучению программированию на python для начинающих. Еще можно записаться!
А также можно почитать:
Tags: python, заметки, ИТ, техника
Trackback from your site.
Mykhailo Poliarush
| #
Добрый день, это вывод вы сделали по каким урокам?
Valerii Synenko
| #
Опис курсу шикарний, теми затронуті правильні, але ведення курсу: “це сюди, те туди, все ж ясно!”, пояснень = 0.
Igor Vlasuyk
| #
“Продолжительность 16 часов (2 дня)”
Это то есть 2 рабочих дня надо полностью быть на тренинге?
И на каком языке программирования будет практика?
Nataliia Koval
| #
Большое спасибо! С расписанием вроде разобралась.
Chmel Viktor
| #
Доброго дня